چالش مهندسی معکوس دوم - دندان مار
توضیحات
دوش چون طاووس مینازیدم اندر باغ وصل
دیگر امروز از فراق یار
میپیچم چو مار
قالب پرچم در این سوال به صورت parcham{some_l33t_string} است.
حل چالش
اول از هر چیز، نوع فایل را بررسی میکنیم:
$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e3ecfce816610debcdf5b324bbff30a86b4dc4d0, stripped
وقتی که برنامه را با ltrace
یا strace
اجرا میکنیم، چیز خاصی عایدمان نمیشود. بنابراین با رادار۲ سراغش میرویم:
$ radare2 -AA a.out [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Check for vtables [x] Type matching analysis for all functions (aaft) [x] Propagate noreturn information [x] Use -AA or aaaa to perform additional experimental analysis. [x] Finding function preludes [x] Enable constraint types analysis for variables [0x00001100]> s main [0x000011e9]> pdgo 0x000011e9 |undefined8 main(void) |{ | int32_t iVar1; | undefined8 uVar2; | int64_t iVar3; | int64_t *piVar4; | int64_t *piVar5; | int64_t var_480h; | int64_t var_40h; | int64_t var_38h; | int32_t var_30h; | undefined4 var_2ch; | int64_t var_28h; | int64_t var_20h; | int64_t var_18h; | int64_t var_10h; | int32_t var_8h; | int64_t var_4h; | 0x00001206 | iVar3 = 0x87; 0x0000120e | piVar4 = (int64_t *)0x2010; 0x0000120e | piVar5 = &var_480h; 0x00001211 | while (iVar3 != 0) { 0x00001211 | iVar3 = iVar3 + -1; 0x00001211 | *piVar5 = *piVar4; 0x00001211 | piVar4 = piVar4 + 1; 0x00001211 | piVar5 = piVar5 + 1; | } 0x0000121c | *(undefined4 *)piVar5 = *(undefined4 *)piVar4; 0x00001229 | *(undefined *)((int64_t)piVar5 + 4) = *(undefined *)((int64_t)piVar4 + 4); 0x0000123a | var_10h = (int64_t)fcn.0000134c; 0x00001245 | var_18h = (int64_t)fcn.00001882; 0x00001250 | var_20h = (int64_t)fcn.00001cca; 0x0000125b | var_28h = (int64_t)fcn.0000188d; 0x00001266 | iVar1 = fcn.00001cd5((int64_t)fcn.0000134c); 0x0000126e | if (iVar1 == -1) { 0x00001270 | uVar2 = 1; | } else { 0x0000127a | fcn.0000134c(); 0x0000127f | var_2ch = 0x43d; 0x00001286 | var_4h._0_4_ = 0; 0x000012bd | while ((int32_t)var_4h < 0x43d) { 0x0000129c | var_40h = (int64_t)(undefined *)(var_10h + (int32_t)var_4h); 0x000012b1 | *(undefined *)(var_10h + (int32_t)var_4h) = *(undefined *)((int64_t)&var_480h + (int64_t)(int32_t)var_4h); 0x000012b3 | var_4h._0_4_ = (int32_t)var_4h + 1; | } 0x000012c3 | iVar1 = (int32_t)var_18h - (int32_t)var_10h; 0x000012cc | var_30h = iVar1 + -0x43d; 0x000012d3 | var_8h = 0; 0x00001309 | while (var_8h < iVar1 + -0x440) { 0x000012ee | var_38h = var_10h + (int64_t)var_8h + 0x43d; 0x000012f9 | *(undefined *)var_38h = 0x90; 0x000012fc | var_8h = var_8h + 1; | } 0x0000131e | sym.imp.printf(0x2008, var_20h); 0x00001336 | sym.imp.printf(0x2008, var_20h); 0x00001340 | sym.imp.putchar(10); 0x00001345 | uVar2 = 0; | } 0x0000134b | return uVar2; |}
تابع main
بسیار کوتاه به نظر میرسد. در جایی تابع printf
یا puts
یا چیزهای مشابه مشاهده نمیشود که بتوان چاپشدن مارپیچها را به آن منسوب کرد. پس احتمالا تابع fcn.0000134c
که در خط 0x0000127a
صدا زده شده، وظیفهی چاپ مارپیچها را بر عهده دارد.
یک حرکت اشتباه، این است که همین ابتدا به بررسی این تابع بپردازیم. اصولا بایستی در مهندسی معکوس، توابعی که درون تابع فعلی صدا زدهشدهاند، به شکل جعبهسیاه ببینیم و تلاش کنیم که همین تابع فعلی را تا حد ممکن درک کنیم. پس به بررسی تابع main
ادامه میدهیم.
یک شرط در 0x0000126e
میبینیم که احتمالا بایستی درون else
برویم. در غیر این صورت برنامه خیلی زود به پایان میرسد و بعید است که پرچم را تا آن لحظه ساخته باشد. پس به درون else
میرویم و فرض میکنیم که شرط نادرست خواهد بود.
در همان ابتدای بلوک مربوط به else
، یک حلقه در خط 0x000012bd
مشاهده میشود. با کمی دقت و به سادگی، میتوان فهمید که این حلقه مشغول به کپیکردن یک قسمت از حافظه درون یک قسمت دیگر است. در کجا کپی میکند؟ در var_10h
که کمی بالاتر مقدارش برابر با آدرس تابع fcn.0000134c
قرار داده است. از کجا کپی میکند؟ از بافر var_480h
که به نظر میرسد مقداردهی نشده است. اما اگر بیشتر دقت کنیم، میبینیم که آدرس این بافر در خط 0x0000120e
مورد استفاده قرار گرفته است و درون piVar5
ریخته شده است. سپس از حافظهای که piVar4
به آن اشاره میکند، به داخل piVar5
کپی شده است.
پس بایستی سراغ حافظهی مربوط به piVar4
برویم و ببینم آنجا چه چیزی نوشته شده است که بدین ترتیب کپی میشود. بنابراین انجامش میدهیم:
[0x000011e9]> s 0x2010 [0x00002010]> px - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00002010 f30f 1efa 5548 89e5 4881 ecd0 0000 00c7 ....UH..H....... 0x00002020 45e4 b50c 0000 c745 fc01 0000 00c7 45e0 E......E......E. 0x00002030 0100 0000 c745 8070 0000 00c7 4584 7200 .....E.p....E.r. 0x00002040 0000 c745 8868 0000 00c7 458c 6d00 0000 ...E.h....E.m... 0x00002050 c745 9041 0000 00c7 4594 3300 0000 c745 .E.A....E.3....E 0x00002060 9830 0000 00c7 459c 3300 0000 c745 a034 .0....E.3....E.4 0x00002070 0000 00c7 45a4 7400 0000 c745 a85f 0000 ....E.t....E._.. 0x00002080 00c7 45ac 3100 0000 c745 b034 0000 00c7 ..E.1....E.4.... 0x00002090 45b4 5900 0000 c745 b870 0000 00c7 45bc E.Y....E.p....E. 0x000020a0 5400 0000 c745 c048 0000 00c7 45c4 6e00 T....E.H....E.n. 0x000020b0 0000 c745 c87d 0000 00c7 8530 ffff ff61 ...E.}.....0...a 0x000020c0 0000 00c7 8534 ffff ff63 0000 00c7 8538 .....4...c.....8 0x000020d0 ffff ff61 0000 00c7 853c ffff ff7b 0000 ...a.....<...{.. 0x000020e0 00c7 8540 ffff ff77 0000 00c7 8544 ffff ...@...w.....D.. 0x000020f0 ff73 0000 00c7 8548 ffff ff6d 0000 00c7 .s.....H...m.... 0x00002100 854c ffff ff5f 0000 00c7 8550 ffff ff55 .L..._.....P...U
به نظر میرسد که محتوای این قسمت از حافظه، نظم خاصی دارد. مثلا حرف E را به تکرر بسیار میتوان مشاهده کرد. از روی بایتهای آن، میتوان حدس زد که احتمالا در این قسمت، تعدادی دستور قرار داده شده است. پس حدس را امتحان میکنیم و دستور pd
را اجرا میکنیم:
[0x00002010]> pd ; DATA XREF from main @ 0x11ff 0x00002010 f30f1efa endbr64 0x00002014 55 push rbp 0x00002015 4889e5 mov rbp, rsp 0x00002018 4881ecd00000. sub rsp, 0xd0 0x0000201f c745e4b50c00. mov dword [rbp - 0x1c], 0xcb5 ; 3253 0x00002026 c745fc010000. mov dword [rbp - 4], 1 0x0000202d c745e0010000. mov dword [rbp - 0x20], 1 ; DATA XREF from fcn.00001d40 @ 0x1d5d 0x00002034 c74580700000. mov dword [rbp - 0x80], 0x70 ; 'p' 0x0000203b c74584720000. mov dword [rbp - 0x7c], 0x72 ; 'r' 0x00002042 c74588680000. mov dword [rbp - 0x78], 0x68 ; 'h' 0x00002049 c7458c6d0000. mov dword [rbp - 0x74], 0x6d ; 'm' 0x00002050 c74590410000. mov dword [rbp - 0x70], 0x41 ; 'A' 0x00002057 c74594330000. mov dword [rbp - 0x6c], 0x33 ; '3' 0x0000205e c74598300000. mov dword [rbp - 0x68], 0x30 ; '0' 0x00002065 c7459c330000. mov dword [rbp - 0x64], 0x33 ; '3' 0x0000206c c745a0340000. mov dword [rbp - 0x60], 0x34 ; '4' 0x00002073 c745a4740000. mov dword [rbp - 0x5c], 0x74 ; 't' 0x0000207a c745a85f0000. mov dword [rbp - 0x58], 0x5f ; '_' 0x00002081 c745ac310000. mov dword [rbp - 0x54], 0x31 ; '1' 0x00002088 c745b0340000. mov dword [rbp - 0x50], 0x34 ; '4' 0x0000208f c745b4590000. mov dword [rbp - 0x4c], 0x59 ; 'Y' 0x00002096 c745b8700000. mov dword [rbp - 0x48], 0x70 ; 'p' 0x0000209d c745bc540000. mov dword [rbp - 0x44], 0x54 ; 'T' 0x000020a4 c745c0480000. mov dword [rbp - 0x40], 0x48 ; 'H' 0x000020ab c745c46e0000. mov dword [rbp - 0x3c], 0x6e ; 'n' 0x000020b2 c745c87d0000. mov dword [rbp - 0x38], 0x7d ; '}' 0x000020b9 c78530ffffff. mov dword [rbp - 0xd0], 0x61 ; 'a' 0x000020c3 c78534ffffff. mov dword [rbp - 0xcc], 0x63 ; 'c' 0x000020cd c78538ffffff. mov dword [rbp - 0xc8], 0x61 ; 'a' 0x000020d7 c7853cffffff. mov dword [rbp - 0xc4], 0x7b ; '{' 0x000020e1 c78540ffffff. mov dword [rbp - 0xc0], 0x77 ; 'w' 0x000020eb c78544ffffff. mov dword [rbp - 0xbc], 0x73 ; 's' 0x000020f5 c78548ffffff. mov dword [rbp - 0xb8], 0x6d ; 'm' 0x000020ff c7854cffffff. mov dword [rbp - 0xb4], 0x5f ; '_' 0x00002109 c78550ffffff. mov dword [rbp - 0xb0], 0x55 ; 'U' 0x00002113 c78554ffffff. mov dword [rbp - 0xac], 0x30 ; '0' 0x0000211d c78558ffffff. mov dword [rbp - 0xa8], 0x62 ; 'b' 0x00002127 c7855cffffff. mov dword [rbp - 0xa4], 0x4e ; 'N' 0x00002131 c78560ffffff. mov dword [rbp - 0xa0], 0x72 ; 'r' 0x0000213b c78564ffffff. mov dword [rbp - 0x9c], 0x5f ; '_' 0x00002145 c78568ffffff. mov dword [rbp - 0x98], 0x34 ; '4' 0x0000214f c7856cffffff. mov dword [rbp - 0x94], 0x63 ; 'c' 0x00002159 c78570ffffff. mov dword [rbp - 0x90], 0x31 ; '1' 0x00002163 c78574ffffff. mov dword [rbp - 0x8c], 0x47 ; 'G' 0x0000216d eb04 jmp 0x2173 ; CODE XREF from section..rodata @ +0x17c 0x0000216f 8345fc01 add dword [rbp - 4], 1 ; CODE XREF from section..rodata @ +0x16d 0x00002173 8b45fc mov eax, dword [rbp - 4] 0x00002176 0fafc0 imul eax, eax 0x00002179 3945e4 cmp dword [rbp - 0x1c], eax 0x0000217c 7ff1 jg 0x216f 0x0000217e 8b45fc mov eax, dword [rbp - 4] 0x00002181 0fafc0 imul eax, eax 0x00002184 3945e4 cmp dword [rbp - 0x1c], eax 0x00002187 7404 je 0x218d 0x00002189 8345fc01 add dword [rbp - 4], 1 ; CODE XREF from section..rodata @ +0x187 0x0000218d 8b45fc mov eax, dword [rbp - 4] 0x00002190 99 cdq 0x00002191 c1ea1f shr edx, 0x1f 0x00002194 01d0 add eax, edx 0x00002196 83e001 and eax, 1 0x00002199 29d0 sub eax, edx 0x0000219b 83f801 cmp eax, 1 0x0000219e 7404 je 0x21a4 0x000021a0 8345fc01 add dword [rbp - 4], 1
خروجی عجیبی به دست آوردیم. تعداد زیادی دستور mov
میبینیم که نویسههای معتبر را جابجا میکنند. اگر کمی دقت کنیم، نظم سادهای در این نویسههای میبینیم. در واقع پرچم، به شکل یکی در میان، دو قسمت شده و این قسمتها پشت سر هم آورده شدهاند.
بنابراین، پرچم به شکل زیر است:
parcham{Aw3s0m3_4Ut0_b1N4rY_p4TcH1nG}