رفع خطای بارگیری با wget

کارهای هکری با فایل‌های باینری به‌بهانهٔ تماشای یک فیلم

دیشب پس از بارگیری یک فیلم سینمایی با wget فهمیدم که باز نمی‌شه. اینجا می‌گم چطوری مشکل رو رفع کردم.

نرم‌افزار wget

‏wget یک ابزار خط‌فرمان باحال برای بارگیری فایل‌هاست. امکانات زیادی داره که البته من همهٔ اون‌ها رو بلد نیستم ولی تقریباً همهٔ چیزهایی که نیاز دارم رو داره. کار باهاش آسونه:

wget https://folansite.com/behmanfile

اگر این دستور رو متوقف کنی و دوباره اجرا کنی، بارگیری فایل رو از اولش آغاز می‌کنه. برای این که بارگیری قبلی رو ادامه بده می‌شه سوییچ ‎-c‬ رو استفاده کرد:

wget -c https://link/

همچنین قابلیتی که برای من خیلی مفیده اینه که می‌تونی همهٔ لینک‌هایی که می‌خواهی دانلود کنی رو بریزی توی یک فایل و ازش بخواهی دانلودشون کنه. این‌طوری:

wget -i links_file

و دستوری که من همیشه استفاده می‌کنم اینه:

wget -ci links_file

این دستور رو با امکاناتی که در محیط توزیعم دارم تنظیم می‌کنم که همیشه شب‌ها که بستهٔ اینترنت دارم خودکار اجرا بشه و صبح‌ها که بسته تموم می‌شه قطع بشه. این‌طوری هر روز فقط محتوای فایل links_file رو ویرایش می‌کنم و فردای اون روز دانلودها آماده هستند.

نرم‌افزار wget گویا یک باگ داره. هنوز نتونسته‌ام به‌درستی دلیل ایجاد شدنش رو پیدا کنم و باگ رو گزارش کنم ولی این باگ باعث می‌شه فایل بارگیری شده خراب بشه. البته در ایران همیشه یک حدس اینه که وضعیت عجیب و داغون اینترنت می‌تونه باعث این بشه.

از کجا فهمیدم فایل خرابه

فایل فیلم بارگیری شده رو با mpv باز کردم. با این دستور:

mpv marmoulak.mkv

و گزارش خطاها رو نگاه کردم. دیدم که می‌گه این اصلاً یک فایل mkv نیست. از اینجا فهمیدم که سرآیند فایل خراب شده.

ولی ممکن بود بقیهٔ فایل هم خراب شده باشه. برای بررسی بیشتر، ۱ مگابایت اول فایل رو دوباره بارگیری کردم. این‌طوری:

wget https://link/ -o new.mkv

از سوییچ ‎-o‍‬ استفاده کردم که دانلود رو روی فایل قبلی ننویسه و از یک اسم جدید استفاده کنه. پس از چند ثانیه بارگیری رو با کلید ترکیبی ‎ctrl+C‬ متوقف کردم. حالا ۲ تا فایل داشتم:

$ ls -lh
-rwxrwxrwx 1 erfan erfan 9.8M Dec  9 18:44 new.mkv
-rwxrwxrwx 1 erfan erfan 2.4G Dec  9 18:53 marmoulak.mkv*

نکتهٔ بامزه: از دسترسی‌های فایل در خروجی دستور بالا می‌تونید حدس بزنید که فایل در یک پارتیشن با فرمت ext یا فرمت‌های یونیکسی دیگر بارگیری نشده چون همهٔ دسترسی‌ها از جمله اجرا رو داره. این یک پارتیشن NTFS است.

حالا با ابزار hexdump می‌تونم اول فایل‌ها رو ببینم.

فایلی که اول بارگیری کرده بودم:

$ hexdump marmoulak.mkv | head
0000000 2d2d 3032 3332 312d 2d32 3930 3120 3a36
0000010 3031 303a 2d38 202d 6820 7474 7370 2f3a
0000020 682f 6d61 6174 6f6d 6976 2e65 6f69 642f
0000030 2f6c 753f 6c72 683d 7474 7370 2f3a 632f
0000040 646c 2e37 6f68 7473 6c64 6e2e 7465 6d2f
0000050 766f 6569 692f 6172 696e 6e61 322f 3230
0000060 2f31 3330 4d2f 7261 6f6d 6c75 6b61 315f
0000070 3830 7030 6d2e 766b 520a 7365 6c6f 6976
0000080 676e 6820 6d61 6174 6f6d 6976 2e65 6f69
0000090 2820 6168 746d 6d61 766f 6569 692e 296f

فایل جدید:

$ hexdump new.mkv | head
0000000 451a a3df 42a3 8186 4201 81f7 4201 81f2
0000010 4204 81f3 4208 8882 616d 7274 736f 616b
0000020 8742 0481 8542 0281 5318 6780 0001 0000
0000030 d195 349b 4d11 749b 4dc0 8cbb ab53 1584
0000040 a949 5366 82ac 0310 bb4d 538c 84ab 5416
0000050 6bae ac53 1082 4d8b 8ebb ab53 1c84 bb53
0000060 536b 84ac cf95 a854 bb4d 538e 84ab 5412
0000070 67c3 ac53 9584 96d1 ec04 bb4f 0000 0000
0000080 0000 0000 0000 0000 0000 0000 0000 0000
*

hexdump

از اینجا می‌شه دید که ۲ تا خروجی متفاوت داریم. اگر بارگیری درست انجام شده بود باید این دو تا یکسان می‌بودند.
تفاوت در فایل‌ها نشون می‌ده بارگیری مشکل داشته و احتمالاً خرابی از فایل اصلی نیست.

نکتهٔ اضافی: در خروجی hexdump یه جایی علامت * رو نوشته. این یعنی چون خط قبلی فایل همه‌ش صفر بوده، در ادامه هم همه‌اش صفره. hexdump خودش کل اون صفرها رو نشون نمی‌ده و این هوشمندی دستوره.

از کجا فهمیدم اشکال از سرآیند فایل است

خب! حالا که فهمیدیم فایل اشکال داره باید بدونم آیا این اشکال فقط از سرآیند فایله یا این که بقیهٔ جاها هم بد بارگیری شده‌اند.

برای این کار هم از hexdump استفاده می‌کنم. می‌خواهم دو تا فایل رو مقایسه کنم. دنبال بایت‌هایی از این فایل در اون یکی می‌گردم.

مقدار بیشتری از فایل سالم رو می‌خونم:

$ hexdump new.mkv | head -n20
0000000 451a a3df 42a3 8186 4201 81f7 4201 81f2
0000010 4204 81f3 4208 8882 616d 7274 736f 616b
0000020 8742 0481 8542 0281 5318 6780 0001 0000
0000030 d195 349b 4d11 749b 4dc0 8cbb ab53 1584
0000040 a949 5366 82ac 0310 bb4d 538c 84ab 5416
0000050 6bae ac53 1082 4d8b 8ebb ab53 1c84 bb53
0000060 536b 84ac cf95 a854 bb4d 538e 84ab 5412
0000070 67c3 ac53 9584 96d1 ec04 bb4f 0000 0000
0000080 0000 0000 0000 0000 0000 0000 0000 0000
*
0001030 0000 0000 0000 1500 a949 4066 2a82 b1d7
0001040 0f83 4042 804d 6ca3 6269 6265 6c6d 7620
0001050 2e31 2e34 2032 202b 696c 6d62 7461 6f72
0001060 6b73 2061 3176 362e 342e 4157 6dad 766b
0001070 656d 6772 2065 3576 2e35 2e30 2030 2728
0001080 6157 7469 6e69 2067 6f46 2072 7053 6361
0001090 2765 2029 3436 622d 7469 8944 4a84 20cb
00010a0 44b0 8861 d808 a863 4996 00ce a473 9890
00010b0 4ba5 53cb 5181 271d 48ed 9a11 7d4c 16b8
00010c0 ae54 416b ae17 d7f8 0181 c573 0181 8183

با توجه به این که بخش زیادی از این فایل با صفر پر شده و بعدش از بایت ۱۰۳۰ (هگز) آنتروپی شروع می‌شه، یک تکه از همونجا رو انتخاب می‌کنم. من رشتهٔ 0f83 4042 804d رو کپی می‌کنم که ازش استفاده کنم.

اون یکی فایل رو هم hexdump می‌کنم و می‌دهم به دستور less که اولاً همهٔ خروجی رو یک جا نشون نده و ثانیاً بتونم داخلش جستجو کنم. less هم از ابزارهای باحال و از خوبان دنیای لینوکسه که امکانات جالبی برای دیدن خروجی یک دستور در اختیارت می‌گذاره.

hexdump Marmoulak.mkv | less

حالا کلید اسلش (/) رو می‌زنم که حالت جستجو فعال بشه. رشته‌ای که کپی کرده بودم رو با کلید ترکیبی ‎`ctrl+shift+v‬ که مال ترمینال من است جای‌گذاری می‌کنم تا جستجو انجام بشه. در نتیجهٔ جستجو می‌بینم که این رشته در فایل پیدا شد. چند بایت دیگر رو هم نگاه می‌کنم. یکسان هستند.

خوشبختانه نه‌تنها این بخش‌ها از فایل‌ها یکسانند بلکه در جای یکسانی هم قرار دارند. یعنی بایت ۱۰۴۰ هر دو فایل مقدار یکسانی داره. یعنی طول بخش خراب‌شده در فایل بیشتر یا کمتر از محتوای اصلی فایل نیست. این کار ما رو آسون‌تر می‌کنه چون لازم نیست چیزی شیفت پیدا کنه.

بررسی بیشتر فایل‌های باینری

برای بررسی بیشتر فایل‌های باینری نیاز به ویرایشگری داریم که به‌جای متن با فایل‌های باینری کار کنه. من از hexedit استفاده کردم که از مخازن توزیعم که دبیان است نصبش کردم:

sudo apt install hexedit

و باهاش هر دو فایل رو باز کردم و نگاه کردم.

$ hexedit Marmoulak.mkv
00000000   2D 2D 32 30  32 33 2D 31  32 2D 30 39  20 31 36 3A  --2023-12-09 16:
00000010   31 30 3A 30  38 2D 2D 20  20 68 74 74  70 73 3A 2F  10:08--  https:/
00000020   2F 68 61 6D  74 61 6D 6F  76 69 65 2E  69 6F 2F 64  /hamtamovie.io/d
00000030   6C 2F 3F 75  72 6C 3D 68  74 74 70 73  3A 2F 2F 63  l/?url=https://c
00000040   6C 64 37 2E  68 6F 73 74  64 6C 2E 6E  65 74 2F 6D  ld7.hostdl.net/m
00000050   6F 76 69 65  2F 69 72 61  6E 69 61 6E  2F 32 30 32  ovie/iranian/202
00000060   31 2F 30 33  2F 4D 61 72  6D 6F 75 6C  61 6B 5F 31  1/03/Marmoulak_1
00000070   30 38 30 70  2E 6D 6B 76  0A 52 65 73  6F 6C 76 69  080p.mkv.Resolvi
00000080   6E 67 20 68  61 6D 74 61  6D 6F 76 69  65 2E 69 6F  ng hamtamovie.io
00000090   20 28 68 61  6D 74 61 6D  6F 76 69 65  2E 69 6F 29   (hamtamovie.io)
000000A0   2E 2E 2E 20  00 00 00 00  00 00 00 00  00 00 00 00  ... ............
000000B0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000000C0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................

و

$ hexedit new.mkv
00000000   1A 45 DF A3  A3 42 86 81  01 42 F7 81  01 42 F2 81  .E...B...B...B..
00000010   04 42 F3 81  08 42 82 88  6D 61 74 72  6F 73 6B 61  .B...B..matroska
00000020   42 87 81 04  42 85 81 02  18 53 80 67  01 00 00 00  B...B....S.g....
00000030   95 D1 9B 34  11 4D 9B 74  C0 4D BB 8C  53 AB 84 15  ...4.M.t.M..S...
00000040   49 A9 66 53  AC 82 10 03  4D BB 8C 53  AB 84 16 54  I.fS....M..S...T
00000050   AE 6B 53 AC  82 10 8B 4D  BB 8E 53 AB  84 1C 53 BB  .kS....M..S...S.
00000060   6B 53 AC 84  95 CF 54 A8  4D BB 8E 53  AB 84 12 54  kS....T.M..S...T
00000070   C3 67 53 AC  84 95 D1 96  04 EC 4F BB  00 00 00 00  .gS.......O.....
00000080   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
00000090   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000000A0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000000B0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000000C0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................

در بالا چند خط اول رو کپی کرده‌ام. قشنگ می‌شه دید که چه اتفاقی افتاده. در فایل سالم اول فایل سرآیندهای مربوط به فرمت قرار دارند.

۴ بایت اول فایل سالم برابر 1A 45 DF A3 است که با نگاه کردن به صفحهٔ ویکی‌پدیای کدهای جادویی فایل‌ها می‌بینیم مربوط به فرمت‌های ویدیویی مثل mkv و webm است.

اما می‌بینیم که در فایل خراب بارگیری شده به طرز عجیبی بخشی از گزارش‌های wget داخل فایل ریخته شده. انگار که خروجی‌اش رو با > داخل یک فایل بریزی.

یه کم بیشتر نگاه کردم و فهمیدم که فقط ۱۲۴ بایت اول فایل خراب شده. البته این رو می‌شه از خروجی دستور hexdump هم فهمید. من ۲۰۰ بایت در نظر می‌گیرم که مطمئن باشم.

چطوری سرآیند یک فایل خراب رو درست کنیم

خب! حالا که فهمیدیم اشکال از کجاست می‌تونیم برای درست کردنش بکوشیم. در گنو ابزار باحال و خفنی به اسم dd داریم که می‌تونه بایت‌ها رو از هر کجایی بخونه و در هر کجایی بنویسه. یک ابزار برای کارهای سطح‌پایین با فایل‌ها، دستگاه‌ها و هر کجایی که امکان خواندن و نوشتن محتوای باینری داشته باشه.

اول از همه از فایل بزرگ یک کپی می‌گیرم که مطمئن باشم اگر خراب‌کاری کردم فایل اصلی هنوز سر جایش باقی بمونه. واقعیتش اینه که پیش از نوشتن این مطلب یک بار دستور رو اشتباه وارد کردم و فایل خراب شد ولی چون پشتیبان داشتم مشکلی ایجاد نشد.

cp Marmoulak.mkv Marmoulak.mkv.backup

حالا خیالم راحته که اگر فایل خراب شد باز هم فایل اصلی رو یه جایی اون گوشه دارم.

حالا دستور زیر رو می‌زنم:

dd bs=200 count=1 if=new.mkv conv=notrunc of=Marmoulak.mkv

دستور بالا ۲۰۰ بایت اول فایل new رو روی فایل Marmoulak می‌نویسه و این‌طوری فایل رو ویرایش می‌کنه.

من برای پیدا کردن شکل درست این دستور از man page اون استفاده کردم:

man dd

همچنین از پوستهٔ خط‌فرمان fish استفاده می‌کنم که با زدن کلید tab می‌تونه بهم کمک زیادی در کامل کردن کنه و سرعتم رو خیلی بیشتر کنه.

حالا سوییچ‌های دستور بالا رو توضیح می‌دهم:

dd bs=200 count=1 if=new.mkv conv=notrunc of=Marmoulak.mkv
  1. ‫‎bs=200‬ یعنی فایل رو در بلوک‌های ۲۰۰ بایتی بخوان. یعنی ۲۰۰ بایت از فایل اول بخون و روی فایل دوم بنویس. بعد برو سراغ ۲۰۰ بایت بعدی و الی آخر
  2. ‫‎count=1‬ یعنی عملیات نوشتن و خواندن رو برای فقط ۱ بلوک انجام بده. ترکیب این با سوییچ bs یعنی فقط ۲۰۰ بایت اول رو ویرایش کن و بعدش عملیات رو متوقف کن.
  3. ‫‎conv=notrunk‬ یعنی سایز فایل خروجی رو کوچک نکن. اگر این رو نمی‌زدم خروجی کلاً ۲۰۰ بایت می‌شد و فایل خراب می‌شد. دقیقاً این کار رو اشتباهی کرده بودم ولی بعدش دستور رو اصلاح کردم.
  4. سوییچ‌های if و of هم که مشخصند. برای اینه که بگیم از کدوم بخونه و روی کدوم بنویسه.

و همین! پس از اجرای دستور بالا یک بار دیگر با همین ابزارهایی که تا الآن استفاده کردم فایل رو بررسی می‌کنم. بعد با mpv بازش می‌کنم. فایل به درستی باز می‌شه و تمام!

مشکل wget چیست

هنوز درست نفهمیده‌ام مشکل از کجاست ولی بهتره گزارشش کنم. در اینترنت دنبال عبارت wget issues می‌گردم تا جای مناسب گزارش رو پیدا کنم. گویا در این سایت باید گزارش‌ها ثبت بشن.

کار درست اینه که اول دنبال این باگ بگردم و اگر نبود اون وقت گزارش کنم. کار با این سایت برایم سخته و هنوز گزارش رو ثبت نکرده‌ام.