গেমগুলি থেকে নেওয়া কিছু পিএনজি ফাইল কেন ভুলভাবে প্রদর্শন করবে?


14

আমি কিছু গেম ফাইল থেকে পিএনজি বের করার বিষয়টি লক্ষ্য করেছি যে চিত্রটি খণ্ড-দিক দিয়ে বিকৃত হয়ে যায়। উদাহরণস্বরূপ, এখানে স্কাইরিমের টেক্সচার ফাইল থেকে বেশ কয়েকটি পিএনজি নেওয়া হয়েছে:

স্কাইরিম থেকে আলোকিত জে পিএনজি স্কাইরিম থেকে আলোকিত কে পিএনজি

এটি কি পিএনজি ফর্ম্যাটে কিছু অস্বাভাবিক প্রকরণ? এই জাতীয় পিএনজিগুলি সঠিকভাবে দেখার জন্য আমার কোন পরিবর্তনগুলি করা দরকার?


1
লোকেরা যাতে স্টাফ তৈরি করতে বাধা দেয় সে জন্য তারা তাদের ফাইলগুলিতে কিছু বিশেষ এনকোডিং রেখেছিল। অথবা হতে পারে আপনি নিষ্কাশন করতে যা ব্যবহার করছেন তা সঠিকভাবে কাজ করে না।
রিচার্ড মার্স্কেল - ড্রাকির

ফাইলগুলি আকারে চিত্রগুলি ছোট করার জন্য এটি এক ধরণের সংক্ষেপণ। এটি আইফোনের অ্যাপগুলিতেও করা হয়।
ডানফোল্ড

1
সামান্য বিট অফ টপিক, কিন্তু এটাই কি একটা পনি?
jcora

উত্তর:


22

এখানে "পুনরুদ্ধার" ইমেজগুলি রয়েছে, লেবারবার্গের আরও গবেষণার জন্য ধন্যবাদ:

final1 final2

প্রত্যাশিত হিসাবে, প্রতি 0x4020 বাইটে 5-বাইট ব্লক চিহ্নিতকারী রয়েছে । ফর্ম্যাটটি নিম্নলিখিত বলে মনে হচ্ছে:

struct marker {
    uint8_t tag;  /* 1 if this is the last marker in the file, 0 otherwise */
    uint16_t len; /* size of the following block (little-endian) */
    uint16_t notlen; /* 0xffff - len */
};

একবার মার্কারটি পড়ার পরে, পরবর্তী marker.lenবাইটগুলি একটি ব্লক তৈরি করে যা ফাইলটির অংশ। marker.notlenএকটি নিয়ন্ত্রণ পরিবর্তনশীল যে যেমন marker.len + marker.notlen == 0xffff। সর্বশেষ ব্লকটি এমন marker.tag == 1

কাঠামো সম্ভবত নিম্নলিখিত হিসাবে রয়েছে। এখনও অজানা মান আছে।

struct file {
    uint8_t name_len;    /* number of bytes in the filename */
                         /* (not sure whether it's uint8_t or uint16_t) */
    char name[name_len]; /* filename */
    uint32_t file_len;   /* size of the file (little endian) */
                         /* eg. "40 25 01 00" is 0x12540 bytes */
    uint16_t unknown;    /* maybe a checksum? */

    marker marker1;             /* first block marker (tag == 0) */
    uint8_t data1[marker1.len]; /* data of the first block */
    marker marker2;             /* second block marker (tag == 0) */
    uint8_t data2[marker2.len]; /* data of the second block */
    /* ... */
    marker lastmarker;                /* last block marker (tag == 1) */
    uint8_t lastdata[lastmarker.len]; /* data of the last block */

    uint32_t unknown2; /* end data? another checksum? */
};

শেষে কী আছে তা আমি বুঝতে পারি নি, তবে পিএনজিরা যেহেতু প্যাডিং গ্রহণ করে, এটি খুব বেশি নাটকীয় নয়। যাইহোক, এনকোডযুক্ত ফাইলের আকারটি পরিষ্কারভাবে নির্দেশ করে যে শেষ 4 বাইট উপেক্ষা করা উচিত ...

যেহেতু ফাইল শুরুর ঠিক আগে আমার কাছে সমস্ত ব্লক চিহ্নিতকারীগুলিতে অ্যাক্সেস ছিল না, তাই আমি এই ডিকোডারটি লিখেছিলাম যা শেষে শুরু হয় এবং ব্লক চিহ্নিতকারীগুলিকে সন্ধান করার চেষ্টা করে। এটি মোটেও শক্তিশালী নয়, এটি আপনার পরীক্ষার চিত্রগুলির জন্য কাজ করেছে:

#include <stdio.h>
#include <string.h>

#define MAX_SIZE (1024 * 1024)
unsigned char buf[MAX_SIZE];

/* Usage: program infile.png outfile.png */
int main(int argc, char *argv[])
{
    size_t i, len, lastcheck;
    FILE *f = fopen(argv[1], "rb");
    len = fread(buf, 1, MAX_SIZE, f);
    fclose(f);

    /* Start from the end and check validity */
    lastcheck = len;
    for (i = len - 5; i-- > 0; )
    {
        size_t off = buf[i + 2] * 256 + buf[i + 1];
        size_t notoff = buf[i + 4] * 256 + buf[i + 3];
        if (buf[i] >= 2 || off + notoff != 0xffff)
            continue;
        else if (buf[i] == 1 && lastcheck != len)
            continue;
        else if (buf[i] == 0 && i + off + 5 != lastcheck)
            continue;
        lastcheck = i;
        memmove(buf + i, buf + i + 5, len - i - 5);
        len -= 5;
        i -= 5;
    }

    f = fopen(argv[2], "wb+");
    fwrite(buf, 1, len, f);
    fclose(f);

    return 0;
}

পুরানো গবেষণা

0x4022দ্বিতীয় চিত্র থেকে বাইট অপসারণ করার পরে, বাইট অপসারণ করার মাধ্যমে আপনি এটি পান 0x8092:

মূল প্রথম ধাপ দ্বিতীয় ধাপ

এটি চিত্রগুলি সত্যই "মেরামত" করে না; আমি এটি পরীক্ষা এবং ত্রুটি করে করেছি। তবে এটি যা বলে তা প্রতি 16384 বাইটে অপ্রত্যাশিত ডেটা রয়েছে। আমার অনুমান যে চিত্রগুলি কিছু প্রকারের ফাইল সিস্টেম কাঠামোভুক্ত এবং অপ্রত্যাশিত ডেটা কেবলমাত্র চিহ্নিতকারীগুলিকে ব্লক করে যা ডেটা পড়ার সময় আপনাকে অপসারণ করা উচিত।

আমি জানি না ঠিক যেখানে ব্লক চিহ্নিতকারী এবং তার আকার, কিন্তু ব্লকের আকারটি অবশ্যই 2 ^ 14 বাইট।

আপনি যদি চিত্রের ঠিক আগে এবং ঠিক পরে প্রদর্শিত হয় তার একটি হেক্সস ডাম্প (কয়েক ডজন বাইট) সরবরাহ করতে পারেন তবে এটি সহায়তা করবে। এটি ব্লকের শুরুতে বা শেষে কী ধরণের তথ্য সংরক্ষণ করা হয় সে সম্পর্কে ইঙ্গিত দেয়।

অবশ্যই আপনার নিষ্কাশন কোডে একটি ত্রুটি রয়েছে এমন সম্ভাবনাও রয়েছে। আপনি যদি নিজের ফাইল অপারেশনের জন্য 16384 বাইটের একটি বাফার ব্যবহার করছেন তবে আমি প্রথমে সেখানে চেক করব।


+1 খুব সহায়ক; আপনি আমাকে যে নেতৃত্ব দিয়েছেন তা দিয়ে আমি এটি খতিয়ে দেখব এবং কিছু অতিরিক্ত তথ্য পোস্ট করব
জেমস তৌবার

এম্বেড করা "ফাইল" ফাইলের নাম সহ একটি দৈর্ঘ্য-উপসর্গযুক্ত স্ট্রিং দিয়ে শুরু হয়; পিএনজি ফাইলগুলির জন্য 89 50 4e 47 ম্যাজিকের আগে 12 বাইট অনুসরণ করা হবে। 12 বাইটগুলি হ'ল: 40 25 01 00 78 9c 00 2a 40 d5 bf
জেমস তৌবার

ভাল কাজ, স্যাম। আমি পাইথন কোডটি আপডেট করেছি যা আসলে বিএসএ ফাইলগুলি সরাসরি একই কাজ করে reads ফলাফলগুলি orbza.s3.amazonaws.com/tillberg/pics.html এ দৃশ্যমান রয়েছে (আমি সেখানে চিত্রের কেবল 1/3 দেখিয়েছি, ফলাফলগুলি প্রদর্শনের জন্য যথেষ্ট)। এটি অনেকগুলি চিত্রের জন্য কাজ করে। অন্যান্য ছবিগুলির সাথে কিছু অন্যান্য জিনিস চলছে। আমি ভাবছি যদি এটি অন্য কোথাও ফল সমাধান 3 বা স্কাইরিমের সমাধান করা হয়েছে তবে।
11-18 অবধি

ভাল কাজ, ছেলেরা! আমি আমার
কোডটিও

18

স্যামের পরামর্শের ভিত্তিতে, আমি জেমসের কোডটি https://github.com/tillberg/skyrim এ লিখেছি এবং স্কাইরিম টেক্সচার বিএসএ ফাইল থেকে সাফল্যের সাথে n_letter.png বের করতে সক্ষম হয়েছি।

চিঠিটি এন

বিএসএ হেডারদের দেওয়া "ফাইল_সাইজ" প্রকৃত চূড়ান্ত ফাইল আকার নয়। এটিতে কিছু শিরোনাম সম্পর্কিত তথ্য পাশাপাশি কিছু ছড়িয়ে ছিটিয়ে থাকা অপ্রয়োজনীয়-দৃশ্যমান ডেটাগুলির এলোমেলো অংশ রয়েছে।

শিরোনামগুলি দেখতে এরকম কিছু দেখায়:

  • 1 বাইট (ফাইলের দৈর্ঘ্য?)
  • ফাইলের পুরো পথ, চরিত্র অনুসারে একটি বাইট
  • জেমস পোস্ট হিসাবে অজানা উত্সের 12 বাইট, (40 25 01 00 78 9c 00 2a 40 d5 bf)।

হেডার বাইটগুলি সরিয়ে ফেলতে, আমি এটি করেছি:

f.seek(file_offset)
data = f.read(file_size)
header_size = 1 + len(folder_path) + len(filename) + 12
d = data[header_size:]

সেখান থেকে আসল পিএনজি ফাইল শুরু হয়। পিএনজি 8-বাইট শুরুর ক্রম থেকে এটি যাচাই করা সহজ।

আমি পিএনজি শিরোনাম পড়ে এবং আইডিএটি অংশে আইএনএড অংশ না হওয়া পর্যন্ত বাইটের সংখ্যা পরিমাপ করে অনুমিত তথ্য প্রস্থের দৈর্ঘ্যের সাথে তুলনা করে অতিরিক্ত বাইটগুলি কোথায় ছিল তা বের করার চেষ্টা করার চেষ্টা করেছি। (এ সম্পর্কিত তথ্যের জন্য, গিথুবে বিএসএপি ফাইলটি পরীক্ষা করে দেখুন)

N_letter.png এ অংশগুলি দেওয়া মাপগুলি হ'ল:

IHDR: 13 bytes
pHYs: 9 bytes
iCCP: 2639 bytes
cHRM: 32 bytes
IDAT: 60625 bytes
IEND: 0 bytes

আমি যখন আইডিএটি অংশ এবং আইএএনডি অংশের পরে প্রকৃত দূরত্বটি পাইথনের (স্ট্রিং.ফাইন্ড () ব্যবহার করে বাইটস গণনা করে) পাই তখন আমি দেখতে পেলাম যে প্রকৃত IDAT দৈর্ঘ্য 60640 বাইট - সেখানে অতিরিক্ত 15 বাইট ছিল ।

সাধারণভাবে, বেশিরভাগ "লেটার" ফাইলের মোট ফাইলের আকারের 16KB এর জন্য অতিরিক্ত 5 বাইট উপস্থিত ছিল। উদাহরণস্বরূপ, প্রায় 73KB এ o_letter.png এর অতিরিক্ত 20 বাইট ছিল আরকেন স্ক্রিবিবলিংয়ের মতো বড় ফাইলগুলিও বেশিরভাগ একই প্যাটার্নটি অনুসরণ করে, যদিও কিছুতে বিজোড় পরিমাণ যুক্ত হয়েছিল (52 বাইট, 12 বাইট বা 32 বাইট)। কি ঘটছে ধারণা নেই।

N_letter.png ফাইলের জন্য, আমি 5-বাইট বিভাগগুলি অপসারণ করার জন্য সঠিক অফসেটগুলি (বেশিরভাগ পরীক্ষা এবং ত্রুটির দ্বারা) সন্ধান করতে সক্ষম হয়েছি।

index = 0x403b
index2 = 0x8070
index3 = 0xc0a0
pngdata = (
  d[0      : (index - 5)] + 
  d[index  : (index2 - 5)] + 
  d[index2 : (index3 - 5)] + 
  d[index3 : ] )
pngfile.write(pngdata)

অপসারণ করা পাঁচটি বাইট বিভাগ:

at 000000: 00 2A 40 D5 BF (<-- included at end of 12 bytes above)
at 00403B: 00 30 40 CF BF
at 008070: 00 2B 40 D4 BF
at 00C0A0: 01 15 37 EA C8

এটির মূল্যের জন্য, অন্যান্য সিকোয়েন্সগুলির সাথে কিছু মিল থাকার কারণে আমি অজানা 12-বাইট বিভাগের শেষ পাঁচটি বাইট অন্তর্ভুক্ত করেছি।

দেখা যাচ্ছে যে তারা প্রতি 16KB নয়, তবে 0x4030 বাইট বিরতিতে রয়েছে।

উপরের সূচকগুলিতে খুব কাছের-না-নিখুঁত ম্যাচগুলি থেকে রক্ষা পেতে, আমি ফলাফল প্রাপ্ত পিএনজি থেকে আইডিএটি খণ্ডের জ্লিব ডিকম্প্রেশনও পরীক্ষা করেছিলাম এবং এটি পাস হয়ে যায়।


"একটি র্যান্ডম @ চিহ্নের জন্য 1 বাইট" ফাইলের নামের স্ট্রিংয়ের দৈর্ঘ্য, আমি বিশ্বাস করি
জেমস তৌবার

প্রতিটি ক্ষেত্রে 5-বাইট বিভাগের মান কত?
জেমস তৌবার

আমি আমার উত্তর সরানো 5-বাইট বিভাগের হেক্স মান সহ আপডেট করেছি। এছাড়াও, আমি 5 বাইট বিভাগের সংখ্যার সাথে নিজেকে মিশ্রিত করেছি (আমি এর আগে রহস্যময় 12-বাইট শিরোনামটিকে 7 বাইট শিরোনাম এবং 5 বাইট পুনরাবৃত্তি বিভাজক হিসাবে গণনা করছিলাম)। আমি এটাও ঠিক করেছিলাম।
অবধি

দ্রষ্টব্য যে (লিটল-এন্ডিয়ান) 0x402A, 0x4030, 0x402B সেই 5-বাইট বিভাগে প্রদর্শিত হবে; এগুলি কি প্রকৃত বিরতি?
জেমস তৌবার

আমি ভেবেছিলাম আমি ইতিমধ্যে বলেছি এটি দুর্দান্ত কাজ, তবে দৃশ্যত আমি তা করি নি। চমৎকার কাজ! :-)
সাম hocevar

3

প্রকৃতপক্ষে, অন্তর্বর্তী 5 বাইটগুলি জিলিব সংক্ষেপণের অংশ।

Http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ এ বিস্তারিত হিসাবে বলা হয়েছে ,

01 ছোট এন্ডিয়ান বিট স্ট্রিং 1 00 00000. 1 চূড়ান্ত ব্লককে নির্দেশ করে, 00 একটি অ-সংকুচিত ব্লক নির্দেশ করে, এবং 00000 অস্টেটে কোনও ব্লকের শুরুটিকে সারিবদ্ধ করার জন্য প্যাডিংয়ের 5 বিট (যা সংকোচিত ব্লকগুলির জন্য প্রয়োজনীয়) , এবং আমার জন্য খুব সুবিধাজনক)। 05 00 ফা এফ এফ সংকুচিত ব্লক (5) এর অষ্টেটের সংখ্যা। একটি সামান্য এন্ডিয়ান 16-বিট পূর্ণসংখ্যার হিসাবে এর পরে এর 1 টির পরিপূরক (!) হয়।

.. সুতরাং একটি 00 একটি 'পরবর্তী' ব্লক (শেষ নয়) নির্দেশ করে এবং পরবর্তী 4 টি বাইটগুলি ব্লকের দৈর্ঘ্য এবং এর বিপরীত।

[সম্পাদনা] একটি আরও নির্ভরযোগ্য উত্স অবশ্যই আরএফসি 1951 (ডিফলেট সংক্ষেপিত ডেটা ফর্ম্যাট স্পেসিফিকেশন), বিভাগ 3.2.4।


1

আপনি কি বাইনারি মোডের পরিবর্তে টেক্সট মোডে ফাইলটি (যেখানে পিএনজি ডেটা প্রদর্শিত হবে এমন লাইন এন্ডিংগুলি সম্ভবত ম্যাংলেড করা হয়েছে) ফাইলটি পড়তে পারবেন?


1
আয়ে। বিষয়টি ইস্যুটির মতো অনেকটা শোনাচ্ছে। এই কোডটি বিবেচনা করে এটি পড়ে: github.com/jtauber/skyrim/blob/master/bsa.py --- নিশ্চিত করেছেন :-)
আর্মিন রোনাচার

না, কোন পার্থক্য নেই।
জেমস তৌবার

@ জেমসটাবার, যদি আপনি সত্যিই নিজের পিএনজি লোডারকে কোডিং করছেন যেহেতু আরমিনের মন্তব্যে বোঝা যাচ্ছে, তবে (ক) এটি আপনার চেষ্টা করা অন্যান্য পিএনজি নিয়ে কাজ করে এবং (খ) স্কাইরিম পিএনজি libpngপড়ার মতো কোনও প্রমাণিত পিএনজি লোডার কি কাজ করে? অন্য কথায়, এটি কি আপনার পিএনজি লোডারটিতে কেবল একটি বাগ রয়েছে?
নাথান রিড

@ নাথানরিড আমি যা করছি তা হ'ল বাইট স্ট্রিমটি বের করা এবং এটি এখানে আপলোড করা; কোনও "লোডার" জড়িত নেই
জেমস তৌবার

3
-1, এই কারণ হতে পারে না। যদি পিএনজি ফাইলগুলি এইভাবে দূষিত হয়ে থাকে তবে চিত্র ডিকোডিং পর্যায়ে ত্রুটিগুলির আগে স্ফীত পর্যায়ে সিআরসি ত্রুটি থাকতে পারে। এছাড়াও, হেডারে প্রত্যাশিত ফাইলটি বাদে ফাইলগুলিতে সিআরএলএফের কোনও উপস্থিতি নেই।
সাম হোচেভার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.