--- title: 'Reverse Engineering ~ Part 1' disqus: hackmd --- # Level 1 ## 1.0 You only use strings command and check correct input. ![image](https://hackmd.io/_uploads/HJdINGDCp.png) ## 1.1 It is similar to level 1.0 # Level 2 ## 2.0 It is similar to level before; however, it swaps indexes '2' and '3'. ## 2.1 It don't show require, so I need to download file challenge and use IDA to read code. ```cpp= read(0, &buf, 5uLL); v3 = BYTE1(buf); BYTE1(buf) = BYTE2(buf); BYTE2(buf) = v3; puts("Checking the received license key!\n"); if ( !memcmp(&buf, aEyfry, 5uLL) ) { sub_12E9(); exit(0); } ``` You can see that, it swaps indexes '1' and '2'. # Level 3 ## 3.0 -Using IDA or you can read instruction after run this challenge. -In IDA: ```cpp= for ( j = 0; j <= 1; ++j ) { v3 = *((_BYTE *)&buf + j); *((_BYTE *)&buf + j) = *((_BYTE *)&buf + 4 - j); *((_BYTE *)&buf + 4 - j) = v3; } ``` ```cpp= if ( !memcmp(&buf, EXPECTED_RESULT, 5uLL) ) { win(); exit(0); } ``` `.data:0000000000004010 EXPECTED_RESULT db 'morjt',0 ; DATA XREF: main+2AF↑o` -So, you need to inpur tjrom ## 3.1 -It similar to level 3.0. # Level 4 Use IDA to read key. # Level 5 ## 5.0 -Use IDA to read expected result: ![image](https://hackmd.io/_uploads/r19oId0A6.png) ```cpp= for ( j = 0; j <= 4; ++j ) *((_BYTE *)&buf + j) ^= 0x88u; ``` -It seem that xor every digit in your input with 0x88. -You need to reverse xor. ```cpp= hex = [0xF8, 0xE2, 0xEE, 0xE0, 0xEC] for i in range(len(hex)): print(chr(hex[i] ^ 0x88), end='') ``` ## 5.1 -Similar to 5.0 # Level 6 ## 6.1 -I will start first at level 6.1 because it doesn't have command what challenge work in IDA ```cpp= for ( i = 0; i <= 7; ++i ) { v3 = *((_BYTE *)buf + i); *((_BYTE *)buf + i) = *((_BYTE *)buf + 15 - i); *((_BYTE *)buf + 15 - i) = v3; } for ( j = 0; j <= 15; ++j ) *((_BYTE *)buf + j) ^= 0x1Du; for ( k = 0; k <= 15; ++k ) { if ( k % 2 ) { if ( k % 2 == 1 ) *((_BYTE *)buf + k) ^= 0xBAu; } else { *((_BYTE *)buf + k) ^= 0x5Eu; } } ``` -Look at this modification: +In first loop from 0 to 7, it swap value at index i and index 15 - i. +Xor all element with 0x1D +Xor value at odd index with 0xBA and even index at 0x5E. ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level6_1.py) # Level 7 ## 7.1 xor at index mod 3 ```cpp= for ( k = 0; k <= 24; ++k ) { v3 = k % 3; if ( k % 3 == 2 ) { *((_BYTE *)&buf + k) ^= 0x13u; } else if ( v3 <= 2 ) { if ( v3 ) { if ( v3 == 1 ) *((_BYTE *)&buf + k) ^= 0xECu; } else { *((_BYTE *)&buf + k) ^= 0xA5u; } } } ``` sort ```cpp= for ( i = 0; i <= 23; ++i ) { for ( j = 0; j < 24 - i; ++j ) { if ( *((_BYTE *)&buf + j) > *((_BYTE *)&buf + j + 1) ) { v7 = *((_BYTE *)&buf + j); *((_BYTE *)&buf + j) = *((_BYTE *)&buf + j + 1); *((_BYTE *)&buf + j + 1) = v7; } } } ``` ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level7_1.py) # Level 8 ## 8.1 ```cpp= puts("Ready to receive your license key!\n"); read(0, &buf, 0x26uLL); for ( i = 0; i <= 18; ++i ) { v9 = *((_BYTE *)&buf + i); *((_BYTE *)&buf + i) = *((_BYTE *)&buf + 37 - i); *((_BYTE *)&buf + 37 - i) = v9; } for ( j = 0; j <= 18; ++j ) { v8 = *((_BYTE *)&buf + j); *((_BYTE *)&buf + j) = *((_BYTE *)&buf + 37 - j); *((_BYTE *)&buf + 37 - j) = v8; } for ( k = 0; k <= 36; ++k ) { for ( m = 0; m < 37 - k; ++m ) { if ( *((_BYTE *)&buf + m) > *((_BYTE *)&buf + m + 1) ) { v7 = *((_BYTE *)&buf + m); *((_BYTE *)&buf + m) = *((_BYTE *)&buf + m + 1); *((_BYTE *)&buf + m + 1) = v7; } } } v3 = BYTE5(v18); BYTE5(v18) = BYTE4(v19); BYTE4(v19) = v3; for ( n = 0; n <= 18; ++n ) { v6 = *((_BYTE *)&buf + n); *((_BYTE *)&buf + n) = *((_BYTE *)&buf + 37 - n); *((_BYTE *)&buf + 37 - n) = v6; } for ( ii = 0; ii <= 18; ++ii ) { v5 = *((_BYTE *)&buf + ii); *((_BYTE *)&buf + ii) = *((_BYTE *)&buf + 37 - ii); *((_BYTE *)&buf + 37 - ii) = v5; } for ( jj = 0; jj <= 18; ++jj ) { v4 = *((_BYTE *)&buf + jj); *((_BYTE *)&buf + jj) = *((_BYTE *)&buf + 37 - jj); *((_BYTE *)&buf + 37 - jj) = v4; } puts("Checking the received license key!\n"); if ( !memcmp(&buf, aZyxxuuuuutspon, 0x26uLL) ) { sub_12E9(); exit(0); } puts("Wrong! No flag for you!"); exit(1); } ``` -Read this code in IDA, you can see the step **Sort**. -You only input your expected input and get the flag =))) # Level 9 ## 9.1 ### Overall ```cpp= void __fastcall __noreturn main(int a1, char **a2, char **a3) { int v3; // eax unsigned __int8 v4; // [rsp+2Dh] [rbp-B3h] BYREF unsigned __int16 v5; // [rsp+2Eh] [rbp-B2h] BYREF int v6; // [rsp+30h] [rbp-B0h] int i; // [rsp+34h] [rbp-ACh] unsigned __int64 v8; // [rsp+38h] [rbp-A8h] char v9[96]; // [rsp+40h] [rbp-A0h] BYREF __int64 v10[2]; // [rsp+A0h] [rbp-40h] BYREF __int64 buf; // [rsp+B0h] [rbp-30h] BYREF __int64 v12; // [rsp+B8h] [rbp-28h] __int64 v13; // [rsp+C0h] [rbp-20h] __int16 v14; // [rsp+C8h] [rbp-18h] char v15; // [rsp+CAh] [rbp-16h] unsigned __int64 v16; // [rsp+D8h] [rbp-8h] v16 = __readfsqword(0x28u); if ( a1 <= 0 ) __assert_fail("argc > 0", "<stdin>", 0x39u, "main"); puts("###"); printf("### Welcome to %s!\n", *a2); puts("###"); putchar(10); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 1uLL); puts( "This license verifier software will allow you to read the flag. However, before you can do so, you must verify that you"); puts("are licensed to read flag files! This program consumes a license key over stdin. Each program may perform entirely"); puts( "different operations on that input! You must figure out (by reverse engineering this program) what that license key is."); puts("Providing the correct license key will net you the flag!\n"); puts("Unfortunately for you, the license key cannot be reversed. You'll have to crack this program.\n"); v6 = 0; v8 = ((unsigned __int64)sub_13A9 & 0xFFFFFFFFFFFFF000LL) - 4096; do v3 = v6++; while ( !mprotect((void *)((v3 << 12) + v8), 0x1000uLL, 7) ); for ( i = 0; i <= 4; ++i ) { printf("Changing byte %d/5.\n", (unsigned int)(i + 1)); printf("Offset (hex) to change: "); __isoc99_scanf("%hx", &v5); printf("New value (hex): "); __isoc99_scanf("%hhx", &v4); *(_BYTE *)(v5 + v8) = v4; printf("The byte has been changed: *%p = %hhx.\n", (const void *)(v8 + v5), v4); } buf = 0LL; v12 = 0LL; v13 = 0LL; v14 = 0; v15 = 0; puts("Ready to receive your license key!\n"); read(0, &buf, 0x1AuLL); MD5_Init(v9); MD5_Update(v9, &buf, 26LL); MD5_Final(v10, v9); memset(&buf, 0, 0x1AuLL); buf = v10[0]; v12 = v10[1]; puts("Checking the received license key!\n"); if ( !memcmp(&buf, &unk_5010, 0x1AuLL) ) { sub_1DAD(); exit(0); } puts("Wrong! No flag for you!"); exit(1); } ``` ***Input*** ```cpp= read(0, &buf, 0x1AuLL); MD5_Init(v9); MD5_Update(v9, &buf, 26LL); MD5_Final(v10, v9); memset(&buf, 0, 0x1AuLL); buf = v10[0]; v12 = v10[1]; ``` - This challenge use MD5 to make private key. - It is easy to see that I input buf, but buf will be set to 0 and change with the value of v10[0]. ***Option change value*** ```cpp= *(_BYTE *)(v5 + v8) = v4; ``` ### Approach :::spoiler ```antlr4= 0x555555555ed6: endbr64 0x555555555eda: push rbp 0x555555555edb: mov rbp,rsp 0x555555555ede: sub rsp,0xe0 0x555555555ee5: mov DWORD PTR [rbp-0xc4],edi 0x555555555eeb: mov QWORD PTR [rbp-0xd0],rsi 0x555555555ef2: mov QWORD PTR [rbp-0xd8],rdx 0x555555555ef9: mov rax,QWORD PTR fs:0x28 0x555555555f02: mov QWORD PTR [rbp-0x8],rax 0x555555555f06: xor eax,eax 0x555555555f08: cmp DWORD PTR [rbp-0xc4],0x0 0x555555555f0f: jg 0x555555555f30 0x555555555f11: lea rcx,[rip+0x14fc] # 0x555555557414 0x555555555f18: mov edx,0x39 0x555555555f1d: lea rsi,[rip+0x11e8] # 0x55555555710c 0x555555555f24: lea rdi,[rip+0x11e9] # 0x555555557114 0x555555555f2b: call 0x5555555551d0 <__assert_fail@plt> 0x555555555f30: lea rdi,[rip+0x11e6] # 0x55555555711d 0x555555555f37: call 0x5555555551b0 <puts@plt> 0x555555555f3c: mov rax,QWORD PTR [rbp-0xd0] 0x555555555f43: mov rax,QWORD PTR [rax] 0x555555555f46: mov rsi,rax 0x555555555f49: lea rdi,[rip+0x11d1] # 0x555555557121 0x555555555f50: mov eax,0x0 0x555555555f55: call 0x555555555190 <printf@plt> 0x555555555f5a: lea rdi,[rip+0x11bc] # 0x55555555711d 0x555555555f61: call 0x5555555551b0 <puts@plt> 0x555555555f66: mov edi,0xa 0x555555555f6b: call 0x5555555551f0 <putchar@plt> 0x555555555f70: mov rax,QWORD PTR [rip+0x30b9] # 0x555555559030 <stdin> 0x555555555f77: mov ecx,0x0 0x555555555f7c: mov edx,0x2 0x555555555f81: mov esi,0x0 0x555555555f86: mov rdi,rax 0x555555555f89: call 0x5555555551e0 <setvbuf@plt> 0x555555555f8e: mov rax,QWORD PTR [rip+0x30a3] # 0x555555559038 <stdout> 0x555555555f95: mov ecx,0x1 0x555555555f9a: mov edx,0x2 0x555555555f9f: mov esi,0x0 0x555555555fa4: mov rdi,rax 0x555555555fa7: call 0x5555555551e0 <setvbuf@plt> 0x555555555fac: lea rdi,[rip+0x1185] # 0x555555557138 0x555555555fb3: call 0x5555555551b0 <puts@plt> 0x555555555fb8: lea rdi,[rip+0x11f1] # 0x5555555571b0 0x555555555fbf: call 0x5555555551b0 <puts@plt> 0x555555555fc4: lea rdi,[rip+0x125d] # 0x555555557228 0x555555555fcb: call 0x5555555551b0 <puts@plt> 0x555555555fd0: lea rdi,[rip+0x12c9] # 0x5555555572a0 0x555555555fd7: call 0x5555555551b0 <puts@plt> 0x555555555fdc: lea rdi,[rip+0x12fd] # 0x5555555572e0 0x555555555fe3: call 0x5555555551b0 <puts@plt> 0x555555555fe8: mov DWORD PTR [rbp-0xb0],0x0 0x555555555ff2: lea rax,[rip+0xfffffffffffff3b0] # 0x5555555553a9 0x555555555ff9: and rax,0xfffffffffffff000 0x555555555fff: sub rax,0x1000 0x555555556005: mov QWORD PTR [rbp-0xa8],rax 0x55555555600c: nop 0x55555555600d: mov eax,DWORD PTR [rbp-0xb0] 0x555555556013: lea edx,[rax+0x1] 0x555555556016: mov DWORD PTR [rbp-0xb0],edx 0x55555555601c: shl eax,0xc 0x55555555601f: movsxd rdx,eax 0x555555556022: mov rax,QWORD PTR [rbp-0xa8] 0x555555556029: add rax,rdx 0x55555555602c: mov edx,0x7 0x555555556031: mov esi,0x1000 0x555555556036: mov rdi,rax 0x555555556039: call 0x555555555180 <mprotect@plt> 0x55555555603e: test eax,eax 0x555555556040: je 0x55555555600d 0x555555556042: mov DWORD PTR [rbp-0xac],0x0 0x55555555604c: jmp 0x55555555611f 0x555555556051: mov eax,DWORD PTR [rbp-0xac] 0x555555556057: add eax,0x1 0x55555555605a: mov esi,eax 0x55555555605c: lea rdi,[rip+0x12dc] # 0x55555555733f 0x555555556063: mov eax,0x0 0x555555556068: call 0x555555555190 <printf@plt> 0x55555555606d: lea rdi,[rip+0x12e0] # 0x555555557354 0x555555556074: mov eax,0x0 0x555555556079: call 0x555555555190 <printf@plt> 0x55555555607e: lea rax,[rbp-0xb2] 0x555555556085: mov rsi,rax 0x555555556088: lea rdi,[rip+0x12de] # 0x55555555736d 0x55555555608f: mov eax,0x0 0x555555556094: call 0x555555555280 <__isoc99_scanf@plt> 0x555555556099: lea rdi,[rip+0x12d1] # 0x555555557371 0x5555555560a0: mov eax,0x0 0x5555555560a5: call 0x555555555190 <printf@plt> 0x5555555560aa: lea rax,[rbp-0xb3] 0x5555555560b1: mov rsi,rax 0x5555555560b4: lea rdi,[rip+0x12c8] # 0x555555557383 0x5555555560bb: mov eax,0x0 0x5555555560c0: call 0x555555555280 <__isoc99_scanf@plt> 0x5555555560c5: movzx ecx,BYTE PTR [rbp-0xb3] 0x5555555560cc: movzx eax,WORD PTR [rbp-0xb2] 0x5555555560d3: movzx edx,ax 0x5555555560d6: mov rax,QWORD PTR [rbp-0xa8] 0x5555555560dd: add rax,rdx 0x5555555560e0: mov edx,ecx 0x5555555560e2: mov BYTE PTR [rax],dl 0x5555555560e4: movzx eax,BYTE PTR [rbp-0xb3] 0x5555555560eb: movzx eax,al 0x5555555560ee: movzx edx,WORD PTR [rbp-0xb2] 0x5555555560f5: movzx ecx,dx 0x5555555560f8: mov rdx,QWORD PTR [rbp-0xa8] 0x5555555560ff: add rcx,rdx 0x555555556102: mov edx,eax 0x555555556104: mov rsi,rcx 0x555555556107: lea rdi,[rip+0x127a] # 0x555555557388 0x55555555610e: mov eax,0x0 0x555555556113: call 0x555555555190 <printf@plt> 0x555555556118: add DWORD PTR [rbp-0xac],0x1 0x55555555611f: cmp DWORD PTR [rbp-0xac],0x4 0x555555556126: jle 0x555555556051 0x55555555612c: mov QWORD PTR [rbp-0x30],0x0 0x555555556134: mov QWORD PTR [rbp-0x28],0x0 0x55555555613c: mov QWORD PTR [rbp-0x20],0x0 0x555555556144: mov WORD PTR [rbp-0x18],0x0 0x55555555614a: mov BYTE PTR [rbp-0x16],0x0 0x55555555614e: lea rdi,[rip+0x125b] # 0x5555555573b0 0x555555556155: call 0x5555555551b0 <puts@plt> 0x55555555615a: lea rax,[rbp-0x30] 0x55555555615e: mov edx,0x1a 0x555555556163: mov rsi,rax 0x555555556166: mov edi,0x0 0x55555555616b: call 0x555555555200 <read@plt> 0x555555556170: lea rax,[rbp-0xa0] 0x555555556177: mov rdi,rax 0x55555555617a: call 0x555555555270 <MD5_Init@plt> 0x55555555617f: lea rcx,[rbp-0x30] 0x555555556183: lea rax,[rbp-0xa0] 0x55555555618a: mov edx,0x1a 0x55555555618f: mov rsi,rcx 0x555555556192: mov rdi,rax 0x555555556195: call 0x555555555230 <MD5_Update@plt> 0x55555555619a: lea rdx,[rbp-0xa0] 0x5555555561a1: lea rax,[rbp-0x40] 0x5555555561a5: mov rsi,rdx 0x5555555561a8: mov rdi,rax 0x5555555561ab: call 0x555555555220 <MD5_Final@plt> 0x5555555561b0: lea rax,[rbp-0x30] 0x5555555561b4: mov edx,0x1a 0x5555555561b9: mov esi,0x0 0x5555555561be: mov rdi,rax 0x5555555561c1: call 0x5555555551a0 <memset@plt> 0x5555555561c6: mov rax,QWORD PTR [rbp-0x40] 0x5555555561ca: mov rdx,QWORD PTR [rbp-0x38] 0x5555555561ce: mov QWORD PTR [rbp-0x30],rax 0x5555555561d2: mov QWORD PTR [rbp-0x28],rdx 0x5555555561d6: lea rdi,[rip+0x11fb] # 0x5555555573d8 0x5555555561dd: call 0x5555555551b0 <puts@plt> 0x5555555561e2: lea rax,[rbp-0x30] 0x5555555561e6: mov edx,0x1a 0x5555555561eb: lea rsi,[rip+0x2e1e] # 0x555555559010 0x5555555561f2: mov rdi,rax 0x5555555561f5: call 0x555555555290 <memcmp@plt> 0x5555555561fa: test eax,eax 0x5555555561fc: jne 0x555555556212 0x5555555561fe: mov eax,0x0 0x555555556203: call 0x555555555dad 0x555555556208: mov edi,0x0 0x55555555620d: call 0x5555555551c0 <exit@plt> 0x555555556212: lea rdi,[rip+0x11e3] # 0x5555555573fc 0x555555556219: call 0x5555555551b0 <puts@plt> 0x55555555621e: mov edi,0x1 0x555555556223: call 0x5555555551c0 <exit@plt> ``` ::: The challenge allows me to change the value at the address starting from the address of v8. ![image](https://hackmd.io/_uploads/rk2RR3yP0.png) ![image](https://hackmd.io/_uploads/BymlyaJwC.png) ![image](https://hackmd.io/_uploads/Sk0gyTJP0.png) It gives me five times to change one byte -> I can change a maximum 10 bytes; however, memcmp compares with the length of 0x1A. Therefore, the idea of changing my buf to a key value is impossible. ***I see a special thing in IDA and when debugging.*** ```cpp= !mprotect((void *)((v3 << 12) + v8), 0x1000uLL, 7) ``` ![image](https://hackmd.io/_uploads/ry7_l6kwR.png) - So, I can change the assembly code =)))). - I will change it to je instead of jne to trigger. ```antlr4= jne: 75 je: 74 ``` # Level 10 ***This challenge is similar to level 9*** # Level 11 This challenge is to create two MD5 hashes and compare them together. Afterwards, it compares license key with ~~my input~~. ## 11.0 ***Overwrite jne after memcmp two hashing values, and then input license key*** ## 11.1 ***It is different from level 11.0.*** ***babyrev_level11.1*** ```cpp= void __fastcall __noreturn main(int a1, char **a2, char **a3) { int v3; // eax unsigned __int8 v4; // [rsp+25h] [rbp-DBh] BYREF unsigned __int16 v5; // [rsp+26h] [rbp-DAh] BYREF int v6; // [rsp+28h] [rbp-D8h] int i; // [rsp+2Ch] [rbp-D4h] int j; // [rsp+30h] [rbp-D0h] int k; // [rsp+34h] [rbp-CCh] unsigned __int64 v10; // [rsp+38h] [rbp-C8h] char v11[96]; // [rsp+40h] [rbp-C0h] BYREF char s1[16]; // [rsp+A0h] [rbp-60h] BYREF char s2[16]; // [rsp+B0h] [rbp-50h] BYREF __int64 v14[2]; // [rsp+C0h] [rbp-40h] BYREF __int64 buf; // [rsp+D0h] [rbp-30h] BYREF __int64 v16; // [rsp+D8h] [rbp-28h] __int64 v17; // [rsp+E0h] [rbp-20h] int v18; // [rsp+E8h] [rbp-18h] __int16 v19; // [rsp+ECh] [rbp-14h] unsigned __int64 v20; // [rsp+F8h] [rbp-8h] v20 = __readfsqword(0x28u); if ( a1 <= 0 ) __assert_fail("argc > 0", "<stdin>", 0x39u, "main"); puts("###"); printf("### Welcome to %s!\n", *a2); puts("###"); putchar(10); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 1uLL); puts( "This license verifier software will allow you to read the flag. However, before you can do so, you must verify that you"); puts("are licensed to read flag files! This program consumes a license key over stdin. Each program may perform entirely"); puts( "different operations on that input! You must figure out (by reverse engineering this program) what that license key is."); puts("Providing the correct license key will net you the flag!\n"); puts("Unfortunately for you, the license key cannot be reversed. You'll have to crack this program.\n"); v6 = 0; v10 = ((unsigned __int64)sub_13A9 & 0xFFFFFFFFFFFFF000LL) - 4096; do v3 = v6++; while ( !mprotect((void *)((v3 << 12) + v10), 0x1000uLL, 7) ); puts("In order to ensure code integrity, the code will be hashed and verified.\n"); MD5_Init(v11); for ( i = 0; i < v6 - 1; ++i ) MD5_Update(v11, (i << 12) + v10, 4096LL); MD5_Final(s1, v11); for ( j = 0; j <= 1; ++j ) { printf("Changing byte %d/2.\n", (unsigned int)(j + 1)); printf("Offset (hex) to change: "); __isoc99_scanf("%hx", &v5); printf("New value (hex): "); __isoc99_scanf("%hhx", &v4); *(_BYTE *)(v5 + v10) = v4; printf("The byte has been changed: *%p = %hhx.\n", (const void *)(v10 + v5), v4); } MD5_Init(v11); for ( k = 0; k < v6 - 1; ++k ) MD5_Update(v11, (k << 12) + v10, 4096LL); MD5_Final(s2, v11); if ( !memcmp(s1, s2, 0x10uLL) ) { puts("The code's integrity is secure!\n"); buf = 0LL; v16 = 0LL; v17 = 0LL; v18 = 0; v19 = 0; puts("Ready to receive your license key!\n"); read(0, &buf, 0x1DuLL); MD5_Init(v11); MD5_Update(v11, &buf, 29LL); MD5_Final(v14, v11); memset(&buf, 0, 0x1DuLL); buf = v14[0]; v16 = v14[1]; puts("Checking the received license key!\n"); if ( !memcmp(&buf, &unk_4010, 0x1DuLL) ) { sub_1923(); exit(0); } puts("Wrong! No flag for you!"); exit(1); } puts("The code's integrity has been breached, aborting!\n"); exit(1); } ``` If you use the same approach as the before level in the first change, you will get the segmentation fault. ***Solution*** :::spoiler ![image](https://hackmd.io/_uploads/HkfR7IGDR.png) - As you can see, this is totally different from the challenge before. [Online x86 / x64 Assembler and Disassembler](https://defuse.ca/online-x86-assembler.htm#disassembly) ![image](https://hackmd.io/_uploads/H1ZVVLMvA.png) - When I disassemble, I see that assembly code. Thus, I try with ```je 0x44``` - ![image](https://hackmd.io/_uploads/HyuYNUfwC.png) ***Change the byte at 0x555555555db7 to 84.*** ::: # Level 12 Baby rev with a different layout. ## 12.0 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level12.py) ## 12.1 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level12_1.py) # Level 13 ## 13.0 ***execute_program*** ```cpp= void __fastcall __noreturn execute_program(__int64 a1) { int v1; // eax int v2; // eax size_t v3; // rax _BOOL4 v4; // [rsp+1Ch] [rbp-94h] char buf[136]; // [rsp+20h] [rbp-90h] BYREF unsigned __int64 v6; // [rsp+A8h] [rbp-8h] v6 = __readfsqword(0x28u); read(0, (void *)(a1 + 52), 8uLL); interpret_imm(a1, 8LL, 84LL); interpret_imm(a1, 32LL, 1LL); interpret_imm(a1, 16LL, 16LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 86LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 249LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 132LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 94LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 213LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 216LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); interpret_imm(a1, 16LL, 16LL); interpret_stm(a1, 8LL, 16LL); interpret_add(a1, 8LL, 32LL); v1 = memcmp((const void *)(a1 + 84), (const void *)(a1 + 52), 8uLL); v4 = v1 == 0; if ( v1 ) { printf("INCORRECT!"); } else { printf("CORRECT! Your flag: "); v2 = open("/flag", 0); v3 = read(v2, buf, 0x64uLL); write(1, buf, v3); } exit(!v4); } ``` ***describe_register*** ```cpp= __int16 *__fastcall describe_register(char a1) { switch ( a1 ) { case 16: return aAbcdsif; case 8: return &aAbcdsif[1]; case 32: return &aAbcdsif[2]; case 1: return &aAbcdsif[3]; case 2: return &aAbcdsif[4]; case 64: return &aAbcdsif[5]; case 4: return &aAbcdsif[6]; } if ( a1 ) return (__int16 *)"?"; return (__int16 *)"NONE"; } ``` - It takes the value of a1, after which return the address of array with the respective index. ***write_register*** ```cpp= _BYTE *__fastcall write_register(_BYTE *a1, char a2, char a3) { _BYTE *result; // rax switch ( a2 ) { case 16: result = a1; a1[256] = a3; break; case 8: result = a1; a1[257] = a3; break; case 32: result = a1; a1[258] = a3; break; case 1: result = a1; a1[259] = a3; break; case 2: result = a1; a1[260] = a3; break; case 64: result = a1; a1[261] = a3; break; case 4: result = a1; a1[262] = a3; break; default: crash(a1, "unknown register"); } return result; } ``` - It takes a2 as the index for table mapping and saves the value of a3 to the array a1 with the respective index. ***read_register*** ```cpp= __int64 __fastcall read_register(unsigned __int8 *a1, char a2) { switch ( a2 ) { case 16: return a1[256]; case 8: return a1[257]; case 32: return a1[258]; case 1: return a1[259]; case 2: return a1[260]; case 64: return a1[261]; } if ( a2 != 4 ) crash(a1, "unknown register"); return a1[262]; } ``` - It takes the value of a2 for table mapping and return the value in array a1 with respective index. ***write_memory*** ```cpp= __int64 __fastcall write_memory(__int64 a1, unsigned __int8 a2, char a3) { __int64 result; // rax result = a2; *(_BYTE *)(a1 + a2) = a3; return result; } ``` - It saves the value of a3 at index a2 of a1. ***interpret_imm*** ```cpp= __int64 __fastcall interpret_imm(__int64 a1, unsigned __int8 a2, unsigned __int8 a3) { unsigned int v3; // ebx const char *v4; // rax v3 = a3; v4 = (const char *)describe_register(a2); printf("[s] IMM %s = %#hhx\n", v4, v3); return write_register(a1, a2, a3); } ``` - It depends on the value of a2(table mapping) to write the value of a3 to array a1 at the respective index(from 256 to 262) ***interpret_stm*** ```cpp= __int64 __fastcall interpret_stm(__int64 a1, unsigned __int8 a2, unsigned __int8 a3) { __int16 *v3; // rbx __int16 *v4; // rax unsigned __int8 v5; // al v3 = describe_register(a3); v4 = describe_register(a2); printf("[s] STM *%s = %s\n", (const char *)v4, (const char *)v3); LODWORD(v3) = (unsigned __int8)read_register(a1, a3); v5 = read_register(a1, a2); return write_memory(a1, v5, (unsigned int)v3); } ``` - First, it takes a3 to get the value at the respective index(256-262) of array a1 and save it to v3(result). - Then, it takes a2 to get the value at the respective index(256-262) of array a1 and save it to v5(index). - Finally, it does `a1[v5] = v3` ***interpret_add*** ```cpp= _BYTE *__fastcall interpret_add(unsigned __int8 *a1, char a2, char a3) { __int16 *v3; // rbx __int16 *v4; // rax char v5; // al v3 = describe_register(a3); v4 = describe_register(a2); printf("[s] ADD %s %s\n", (const char *)v4, (const char *)v3); LOBYTE(v3) = read_register(a1, a2); v5 = read_register(a1, a3); return write_register(a1, a2, (unsigned __int8)v3 + v5); } ``` - First, it takes a2 to get the value at the respective index(256-262) of array a1 and save it to v3. - Next, it takes a3 to get the value at the respective index(256-262) of array a1 and save it to v5. - Then, it relies on the value of a2 and save (v3 + v5) to the respective index(256-262) of array a1. ***Debug in gdb to get the informations and write them to script*** ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level13.py) ## 13.1 - It is totally similar to 13.0, so I use trick to solve quickly this level. ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level13_1.py) # Level 14 ## 14.0 In this level, it gives me one more function. ***interpret_sys*** ```cpp= int __fastcall interpret_sys(unsigned __int8 *a1, unsigned __int8 a2, unsigned __int8 a3) { const char *v3; // rax unsigned __int8 v4; // al unsigned __int64 v5; // rax unsigned __int8 v6; // al unsigned __int64 v7; // rax unsigned __int8 v8; // al unsigned __int8 v9; // al int result; // eax unsigned int v11; // ebx const char *v12; // rax v3 = (const char *)describe_register(a3); printf("[s] SYS %#hhx %s\n", a2, v3); if ( (a2 & 0x20) != 0 ) { puts("[s] ... open"); v4 = sys_open(a1, &a1[a1[256]], a1[257], a1[258]); write_register(a1, a3, v4); } if ( (a2 & 1) != 0 ) { puts("[s] ... read_memory"); v5 = a1[258]; if ( 256 - a1[257] <= v5 ) LOBYTE(v5) = -a1[257]; v6 = sys_read(a1, a1[256], &a1[a1[257]], (unsigned __int8)v5); write_register(a1, a3, v6); } if ( (a2 & 8) != 0 ) { puts("[s] ... write"); v7 = a1[258]; if ( 256 - a1[257] <= v7 ) LOBYTE(v7) = -a1[257]; v8 = sys_write(a1, a1[256], &a1[a1[257]], (unsigned __int8)v7); write_register(a1, a3, v8); } if ( (a2 & 4) != 0 ) { puts("[s] ... sleep"); v9 = sys_sleep(a1, a1[256]); write_register(a1, a3, v9); } result = a2 & 0x10; if ( (a2 & 0x10) != 0 ) { puts("[s] ... exit"); sys_exit(a1, a1[256]); } if ( a3 ) { v11 = (unsigned __int8)read_register(a1, a3); v12 = (const char *)describe_register(a3); return printf("[s] ... return value (in register %s): %#hhx\n", v12, v11); } return result; } ``` ![image](https://hackmd.io/_uploads/rysildUu0.png) - As you see, in function interpret_sys, it only call `[s] ... read_memory`, so I only notice it. ```cpp= if ( (a2 & 1) != 0 ) { puts("[s] ... read_memory"); v5 = a1[258]; if ( 256 - a1[257] <= v5 ) LOBYTE(v5) = -a1[257]; v6 = sys_read(a1, a1[256], &a1[a1[257]], (unsigned __int8)v5); write_register(a1, a3, v6); } ``` ```cpp= ssize_t __fastcall sys_read(__int64 a1, int a2, void *a3, size_t a4) { return read(a2, a3, a4); } ``` ***In this level, this function will take my input, whose length is v5(a1[258]) and save it into the array a1, from index 257.*** ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level14.py) ## 14.1 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level14_1.py) # Level 15 ## 15.0 ***execute_program*** ```cpp= __int64 __fastcall execute_program(__int64 a1) { _BOOL4 v2; // [rsp+1Ch] [rbp-4h] interpret_imm(a1, 1LL, 79LL); interpret_imm(a1, 8LL, 8LL); interpret_imm(a1, 64LL, 0LL); interpret_sys(a1, 2LL, 64LL); interpret_imm(a1, 1LL, 111LL); interpret_imm(a1, 8LL, 1LL); interpret_imm(a1, 64LL, 99LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 15LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 90LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 125LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 120LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 1LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 143LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); interpret_imm(a1, 64LL, 87LL); interpret_stm(a1, 1LL, 64LL); interpret_add(a1, 1LL, 8LL); v2 = memcmp((const void *)(a1 + 111), (const void *)(a1 + 79), 8uLL) == 0; interpret_imm(a1, 64LL, 1LL); interpret_imm(a1, 1LL, 0LL); interpret_imm(a1, 8LL, 1LL); if ( v2 ) { interpret_imm(a1, 2LL, 67LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 79LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 82LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 82LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 69LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 67LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 84LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 33LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 32LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 89LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 111LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 117LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 114LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 32LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 102LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 108LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 97LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 103LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 58LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 10LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 47LL); interpret_imm(a1, 1LL, 0LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 2LL, 102LL); interpret_imm(a1, 1LL, 1LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 2LL, 108LL); interpret_imm(a1, 1LL, 2LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 2LL, 97LL); interpret_imm(a1, 1LL, 3LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 2LL, 103LL); interpret_imm(a1, 1LL, 4LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 2LL, 0LL); interpret_imm(a1, 1LL, 5LL); interpret_stm(a1, 1LL, 2LL); interpret_imm(a1, 64LL, 0LL); interpret_imm(a1, 1LL, 0LL); interpret_sys(a1, 32LL, 64LL); interpret_imm(a1, 8LL, 100LL); interpret_sys(a1, 2LL, 8LL); interpret_imm(a1, 64LL, 1LL); interpret_sys(a1, 8LL, 8LL); interpret_imm(a1, 64LL, 0LL); } else { interpret_imm(a1, 2LL, 73LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 78LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 67LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 79LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 82LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 82LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 69LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 67LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 84LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 2LL, 33LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); interpret_imm(a1, 64LL, 1LL); } interpret_imm(a1, 2LL, 10LL); interpret_stm(a1, 1LL, 2LL); interpret_sys(a1, 8LL, 64LL); return interpret_sys(a1, 16LL, 64LL); } ``` - In this level, I must to make `v2 != 0` to get the flag. The difference between this level and the previous level is that function interpret_sys has options `[s] ... write` and `[s] ... exit` - ![image](https://hackmd.io/_uploads/SyRxudIu0.png) ```cpp= if ( (a2 & 0x10) != 0 ) { puts("[s] ... exit"); exit(a1[256]); } ``` - It is simply that the program exits ```cpp= if ( (a2 & 8) != 0 ) { puts("[s] ... write"); v7 = a1[258]; if ( 256 - a1[257] <= v7 ) LOBYTE(v7) = -a1[257]; v8 = write(a1[256], &a1[a1[257]], (unsigned __int8)v7); write_register(a1, a3, v8); } ``` - It writes the value at index a1[257] of array a1 with length 1 to stdout ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level15.py) ## 15.1 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level15_1.py) # Level 16 ## 16.0 In this level, we have two more functions. ***interpret_ldm*** ```cpp= _BYTE *__fastcall interpret_ldm(unsigned __int8 *a1, char a2, char a3) { __int16 *v3; // rbx __int16 *v4; // rax unsigned __int8 v5; // al char memory; // al v3 = describe_register(a3); v4 = describe_register(a2); printf("[s] LDM %s = *%s\n", (const char *)v4, (const char *)v3); v5 = read_register(a1, a3); memory = read_memory((__int64)a1, v5); return write_register(a1, a2, memory); } ``` ***interpret_cmp*** ```cpp= unsigned __int64 __fastcall interpret_cmp(unsigned __int8 *a1, char a2, char a3) { __int16 *v3; // rbx __int16 *v4; // rax unsigned __int64 result; // rax unsigned __int8 v7; // [rsp+1Eh] [rbp-12h] unsigned __int8 v8; // [rsp+1Fh] [rbp-11h] v3 = describe_register(a3); v4 = describe_register(a2); printf("[s] CMP %s %s\n", (const char *)v4, (const char *)v3); v7 = read_register(a1, a2); v8 = read_register(a1, a3); a1[262] = 0; if ( v7 < v8 ) a1[262] |= 2u; if ( v7 > v8 ) a1[262] |= 4u; if ( v7 == v8 ) a1[262] |= 0x10u; result = v7; if ( v7 != v8 ) { result = (unsigned __int64)a1; a1[262] |= 1u; } if ( !v7 && !v8 ) { result = (unsigned __int64)a1; a1[262] |= 8u; } return result; } ``` ***execute_program*** ```cpp= int __fastcall execute_program(unsigned __int8 *a1) { _BOOL4 v2; // [rsp+1Ch] [rbp-4h] interpret_imm((__int64)a1, 0x10u, 0x73u); interpret_imm((__int64)a1, 1u, 8u); interpret_imm((__int64)a1, 0x20u, 0); interpret_sys(a1, 0x20u, 0x20u); interpret_imm((__int64)a1, 0x10u, 0x93u); interpret_imm((__int64)a1, 1u, 1u); interpret_imm((__int64)a1, 0x20u, 0xB2u); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0x8Au); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0x6Eu); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0x5Au); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0xAFu); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0x33u); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0xE9u); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x20u, 0xB9u); interpret_stm(a1, 16LL, 32LL); interpret_add(a1, 0x10u, 1u); interpret_imm((__int64)a1, 0x10u, 0x93u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x73u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); v2 = (a1[262] & 0x10) != 0; interpret_imm((__int64)a1, 0x10u, 0x94u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x74u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x95u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x75u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x96u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x76u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x97u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x77u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x98u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x78u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x99u); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x79u); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x10u, 0x9Au); interpret_ldm(a1, 16, 16); interpret_imm((__int64)a1, 0x20u, 0x7Au); interpret_ldm(a1, 32, 32); interpret_cmp(a1, 32, 16); if ( (a1[262] & 0x10) == 0 ) v2 = 0; interpret_imm((__int64)a1, 0x20u, 1u); interpret_imm((__int64)a1, 0x10u, 0); interpret_imm((__int64)a1, 1u, 1u); if ( v2 ) { interpret_imm((__int64)a1, 8u, 0x43u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x4Fu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x52u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x52u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x45u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x43u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x54u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x21u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x20u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x59u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x6Fu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x75u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x72u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x20u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x66u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x6Cu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x61u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x67u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x3Au); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0xAu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x2Fu); interpret_imm((__int64)a1, 0x10u, 0); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 8u, 0x66u); interpret_imm((__int64)a1, 0x10u, 1u); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 8u, 0x6Cu); interpret_imm((__int64)a1, 0x10u, 2u); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 8u, 0x61u); interpret_imm((__int64)a1, 0x10u, 3u); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 8u, 0x67u); interpret_imm((__int64)a1, 0x10u, 4u); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 8u, 0); interpret_imm((__int64)a1, 0x10u, 5u); interpret_stm(a1, 16LL, 8LL); interpret_imm((__int64)a1, 0x20u, 0); interpret_imm((__int64)a1, 0x10u, 0); interpret_sys(a1, 8u, 0x20u); interpret_imm((__int64)a1, 1u, 0x64u); interpret_sys(a1, 0x20u, 1u); interpret_imm((__int64)a1, 0x20u, 1u); interpret_sys(a1, 2u, 1u); interpret_imm((__int64)a1, 0x20u, 0); } else { interpret_imm((__int64)a1, 8u, 0x49u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x4Eu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x43u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x4Fu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x52u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x52u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x45u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x43u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x54u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 8u, 0x21u); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); interpret_imm((__int64)a1, 0x20u, 1u); } interpret_imm((__int64)a1, 8u, 0xAu); interpret_stm(a1, 16LL, 8LL); interpret_sys(a1, 2u, 0x20u); return interpret_sys(a1, 1u, 0x20u); } ``` I notice the special execute_program - From line 5 to line 34: create a license key - From line 35 to 92: in every next stage: - interpret_imm → interpret_ldm → interpret_imm → interpret_ldm → interpret_cmp - Every interpret function are the same, except for interpret_ldm. - `interpret_ldm(a1, 16, 16);` - `interpret_ldm(a1, 32, 32);` I will get the first stage to explain ```python= #save the value at the third agrument to a1[257] interpret_imm(a1, 0x10, 0x93) #read the value at a1[257], after which make it an index to read at this index and store it at a1[257] # index = a1[257] # a1[257] = a1[index] interpret_ldm(a1, 16, 16) #save the value at the third agrument to a1[256] interpret_imm(a1, 0x20, 0x73) #read the value at a1[256], after which make it an index to read at this index and store it at a1[256] # index = a1[256] # a1[256] = a1[index] interpret_ldm(a1, 32, 32) #compare the value between a1[256] and a1[257] interpret_cmp(a1, 32, 16) ``` In the other stage, the value of the the third agrument in function interpret_imm increase from 0x94 → 0x9A and from 0x74 → 0x7A To get the flag, I need to have make `v2 != 0` - → `a1[256] = a1[257]` After this level makes a license key, it has the value at index 0x94 → 0x9A. I can get them by reversing. And the value 0x74 → 0x7A is my input. ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level16.py) ## 16.1 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level16_1.py) # Level 17 ## 17.0 - It is simiar to the previous level; however, there is a small difference. ```cpp= __int64 __fastcall interpret_stm(unsigned __int8 *a1, char a2, char a3) { __int16 *v3; // rbx __int16 *v4; // rax unsigned __int8 v5; // al v3 = describe_register(a3); v4 = describe_register(a2); printf("[s] STM *%s = %s\n", (const char *)v4, (const char *)v3); LOBYTE(v3) = read_register(a1, a3); v5 = read_register(a1, a2); return write_memory((__int64)a1, v5, (char)v3); } ``` ```cpp= return write_memory((__int64)a1, v5, (char)v3); ``` - It is (char)v3 instead of (unsigned int)v3. So, let's modify the script a little ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level17.py) ## 17.1 ***execute_program*** ```cpp= __int64 __fastcall sub_198C(_BYTE *a1) { _BOOL4 v2; // [rsp+1Ch] [rbp-4h] interpret_imm(a1, 4, 53); interpret_imm(a1, 16, 6); interpret_imm(a1, 2, 0); interpret_sys(a1, 16LL, 2LL); interpret_imm(a1, 4, 85); interpret_imm(a1, 16, 1); interpret_imm(a1, 2, 212); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 2, 29); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 2, 121); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 2, 68); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 2, 42); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 2, 204); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 4, 53); interpret_imm(a1, 16, 1); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 110); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 211); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 253); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 140); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 165); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_ldm((__int64)a1, 2u, 4u); interpret_imm(a1, 32, 215); interpret_add(a1, 2LL, 32LL); interpret_stm(a1, 4LL, 2LL); interpret_add(a1, 4LL, 16LL); interpret_imm(a1, 4, 85); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 53); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); v2 = (a1[262] & 4) != 0; interpret_imm(a1, 4, 86); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 54); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); if ( (a1[262] & 4) == 0 ) v2 = 0; interpret_imm(a1, 4, 87); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 55); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); if ( (a1[262] & 4) == 0 ) v2 = 0; interpret_imm(a1, 4, 88); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 56); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); if ( (a1[262] & 4) == 0 ) v2 = 0; interpret_imm(a1, 4, 89); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 57); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); if ( (a1[262] & 4) == 0 ) v2 = 0; interpret_imm(a1, 4, 90); interpret_ldm((__int64)a1, 4u, 4u); interpret_imm(a1, 2, 58); interpret_ldm((__int64)a1, 2u, 2u); interpret_cmp(a1, 2LL, 4LL); if ( (a1[262] & 4) == 0 ) v2 = 0; interpret_imm(a1, 2, 1); interpret_imm(a1, 4, 0); interpret_imm(a1, 16, 1); if ( v2 ) { interpret_imm(a1, 32, 67); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 79); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 82); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 82); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 69); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 67); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 84); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 33); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 32); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 89); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 111); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 117); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 114); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 32); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 102); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 108); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 97); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 103); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 58); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 10); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 47); interpret_imm(a1, 4, 0); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 32, 102); interpret_imm(a1, 4, 1); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 32, 108); interpret_imm(a1, 4, 2); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 32, 97); interpret_imm(a1, 4, 3); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 32, 103); interpret_imm(a1, 4, 4); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 32, 0); interpret_imm(a1, 4, 5); interpret_stm(a1, 4LL, 32LL); interpret_imm(a1, 2, 0); interpret_imm(a1, 4, 0); interpret_sys(a1, 1LL, 2LL); interpret_imm(a1, 16, 100); interpret_sys(a1, 16LL, 16LL); interpret_imm(a1, 2, 1); interpret_sys(a1, 4LL, 16LL); interpret_imm(a1, 2, 0); } else { interpret_imm(a1, 32, 73); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 78); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 67); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 79); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 82); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 82); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 69); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 67); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 84); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 32, 33); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); interpret_imm(a1, 2, 1); } interpret_imm(a1, 32, 10); interpret_stm(a1, 4LL, 32LL); interpret_sys(a1, 4LL, 2LL); return interpret_sys(a1, 32LL, 2LL); } ``` - I renamed the name of the function for easy reading. ***It is similar to level 17.0; however, it has some differences** In some functions, the type of agrument is char - `interpret_add(unsigned __int8 *a1, char a2, char a3)` - `interpret_ldm(unsigned __int8 *a1, char a2, char a3)` - `interpret_cmp(unsigned __int8 *a1, char a2, char a3)` From line 5 to line 31: create license key or do something. In the next every stage, I notice that there is some similar region. I will take one of them to explain(my input is **abcdef**) ```cpp= interpret_imm(a1, 32, 110); // a1[259] = 110 interpret_add(a1, 2LL, 32LL); // a1[256] = a1[256] + a1[259] interpret_stm(a1, 4LL, 2LL); // a1[a1[257]] = a1[256] interpret_add(a1, 4LL, 16LL); // a1[257] = a1[257] + a1[258] interpret_ldm((__int64)a1, 2u, 4u); // a1[256] = a1[a1[257]] ``` ![image](https://hackmd.io/_uploads/HyKxVp8d0.png) ***Overall, it takes each bytes in my input and increases or decreases with the specified value.*** ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level17_1.py) # Level 18 ## 18.0 ***execute_program*** ```cpp= __int64 __fastcall execute_program(__int64 a1) { _BOOL4 v2; // [rsp+1Ch] [rbp-4h] interpret_imm(a1, 4LL, 96LL); interpret_imm(a1, 1LL, 9LL); interpret_imm(a1, 32LL, 0LL); interpret_sys(a1, 2LL, 32LL); interpret_imm(a1, 4LL, 128LL); interpret_imm(a1, 1LL, 1LL); interpret_imm(a1, 32LL, 65LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 87LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 208LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 192LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 159LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 211LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 236LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 57LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 65LL); interpret_stm(a1, 4LL, 32LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 4LL, 128LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 38LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 96LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); v2 = (*(_BYTE *)(a1 + 262) & 0x10) != 0; interpret_imm(a1, 4LL, 129LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 224LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 97LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 130LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 194LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 98LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 131LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 77LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 99LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 132LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 76LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 100LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 133LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 59LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 101LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 134LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 120LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 102LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 135LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 142LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 103LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 4LL, 136LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 131LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 104LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); if ( (*(_BYTE *)(a1 + 262) & 0x10) == 0 ) v2 = 0; interpret_imm(a1, 32LL, 1LL); interpret_imm(a1, 4LL, 0LL); interpret_imm(a1, 1LL, 1LL); if ( v2 ) { interpret_imm(a1, 16LL, 67LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 79LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 82LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 82LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 69LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 67LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 84LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 33LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 32LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 89LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 111LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 117LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 114LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 32LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 102LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 108LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 97LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 103LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 58LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 10LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 47LL); interpret_imm(a1, 4LL, 0LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 16LL, 102LL); interpret_imm(a1, 4LL, 1LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 16LL, 108LL); interpret_imm(a1, 4LL, 2LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 16LL, 97LL); interpret_imm(a1, 4LL, 3LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 16LL, 103LL); interpret_imm(a1, 4LL, 4LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 16LL, 0LL); interpret_imm(a1, 4LL, 5LL); interpret_stm(a1, 4LL, 16LL); interpret_imm(a1, 32LL, 0LL); interpret_imm(a1, 4LL, 0LL); interpret_sys(a1, 1LL, 32LL); interpret_imm(a1, 1LL, 100LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 32LL, 1LL); interpret_sys(a1, 16LL, 1LL); interpret_imm(a1, 32LL, 0LL); } else { interpret_imm(a1, 16LL, 73LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 78LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 67LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 79LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 82LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 82LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 69LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 67LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 84LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 16LL, 33LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); interpret_imm(a1, 32LL, 1LL); } interpret_imm(a1, 16LL, 10LL); interpret_stm(a1, 4LL, 16LL); interpret_sys(a1, 16LL, 32LL); return interpret_sys(a1, 8LL, 32LL); } ``` - From line 5 too line 37: create license key - In the every next stages, this function has the similar part - interpret_imm → interpret_ldm → interpret_imm → interpret_add → interpret_imm → interpret_ldm → interpret_cmp The first part ```cpp= interpret_imm(a1, 4LL, 128LL); interpret_ldm(a1, 4LL, 4LL); interpret_imm(a1, 1LL, 38LL); interpret_add(a1, 4LL, 1LL); interpret_imm(a1, 32LL, 96LL); interpret_ldm(a1, 32LL, 32LL); interpret_cmp(a1, 32LL, 4LL); ``` It does ```ccp= //a1[257] = 128 interpret_imm(a1, 4, 128) //index = a1[257] (=128) //a1[257] = a1[index] interpret_ldm(a1, 4, 4) //a1[258] = 38 interpret_imm(a1, 1, 38) //a1[257] += a1[258] interpret_add(a1, 4, 1) //a1[256] = 96 interpret_imm(a1, 32, 96) //index = a1[256] //memory = a1[index] //a1[256] = memory // ~~~ a1[256] = a1[96] interpret_ldm(a1, 32, 32) //compare a1[256] and a1[257] interpret_cmp(a1, 32, 4) ``` ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level18.py) ## 18.1 ***execute_program*** ```cpp= __int64 __fastcall sub_198C(_BYTE *a1) { _BOOL4 v2; // [rsp+1Ch] [rbp-4h] interpret_imm(a1, 32, 96); interpret_imm(a1, 16, 12); interpret_imm(a1, 1, 0); interpret_sys(a1, 32LL, 1LL); interpret_imm(a1, 32, 128); interpret_imm(a1, 16, 1); interpret_imm(a1, 1, 170); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 150); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 100); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 106); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 11); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 238); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 101); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 9); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 168); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 33); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 105); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 8); interpret_stm(a1, 32LL, 1LL); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 32, 128); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 17); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 96); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); v2 = (a1[262] & 2) != 0; interpret_imm(a1, 32, 129); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 1); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 97); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 130); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 203); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 98); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 131); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 195); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 99); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 132); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 148); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 100); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 133); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 157); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 101); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 134); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 216); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 102); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 135); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 84); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 103); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 136); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 51); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 104); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 137); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 199); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 105); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 138); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 8); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 106); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 32, 139); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 41); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 107); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); if ( (a1[262] & 2) == 0 ) v2 = 0; interpret_imm(a1, 1, 1); interpret_imm(a1, 32, 0); interpret_imm(a1, 16, 1); if ( v2 ) { interpret_imm(a1, 2, 67); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 79); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 82); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 82); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 69); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 67); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 84); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 33); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 32); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 89); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 111); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 117); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 114); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 32); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 102); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 108); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 97); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 103); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 58); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 10); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 47); interpret_imm(a1, 32, 0); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 2, 102); interpret_imm(a1, 32, 1); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 2, 108); interpret_imm(a1, 32, 2); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 2, 97); interpret_imm(a1, 32, 3); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 2, 103); interpret_imm(a1, 32, 4); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 2, 0); interpret_imm(a1, 32, 5); interpret_stm(a1, 32LL, 2LL); interpret_imm(a1, 1, 0); interpret_imm(a1, 32, 0); interpret_sys(a1, 16LL, 1LL); interpret_imm(a1, 16, 100); interpret_sys(a1, 32LL, 16LL); interpret_imm(a1, 1, 1); interpret_sys(a1, 2LL, 16LL); interpret_imm(a1, 1, 0); } else { interpret_imm(a1, 2, 73); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 78); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 67); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 79); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 82); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 82); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 69); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 67); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 84); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 2, 33); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); interpret_imm(a1, 1, 1); } interpret_imm(a1, 2, 10); interpret_stm(a1, 32LL, 2LL); interpret_sys(a1, 2LL, 1LL); return interpret_sys(a1, 4LL, 1LL); } ``` - From line 5 too line 46: create license key - In the every next stages, this function has the similar part - interpret_imm → interpret_ldm → interpret_imm → interpret_add → interpret_imm → interpret_ldm → interpret_cmp The first part ```cpp= interpret_imm(a1, 32, 128); interpret_ldm(a1, 32LL, 32LL); interpret_imm(a1, 16, 17); interpret_add(a1, 32LL, 16LL); interpret_imm(a1, 1, 96); interpret_ldm(a1, 1LL, 1LL); interpret_cmp(a1, 1LL, 32LL); ``` It does ```ccp= //a1[257] = 128 interpret_imm(a1, 32, 128) //index = a1[257] (=128) ///a1[257] = a1[index] interpret_ldm(a1, 32, 32) //a1[258] = 17 interpret_imm(a1, 16, 17) //a1[257] += a1[258] interpret_add(a1, 32, 16) //a1[256] = 96 interpret_imm(a1, 1, 96) //index = a1[256] //memory = a1[index] //a1[256] = memory // ~~~ a1[256] = a1[96] interpret_ldm(a1, 1, 1) //compare a1[256] and a1[257] interpret_cmp(a1, 1, 32) ``` ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level18_1.py) # Level 19 ## 19.0 ***main*** ```cpp= int __fastcall __noreturn main(int argc, const char **argv, const char **envp) { __int64 dest[128]; // [rsp+10h] [rbp-410h] BYREF int v4; // [rsp+410h] [rbp-10h] __int16 v5; // [rsp+414h] [rbp-Ch] char v6; // [rsp+416h] [rbp-Ah] unsigned __int64 v7; // [rsp+418h] [rbp-8h] v7 = __readfsqword(0x28u); printf("[+] Welcome to %s!\n", *argv); puts("[+] This challenge is an custom emulator. It emulates a completely custom"); puts("[+] architecture that we call \"Yan85\"! You'll have to understand the"); puts("[+] emulator to understand the architecture, and you'll have to understand"); puts("[+] the architecture to understand the code being emulated, and you will"); puts("[+] have to understand that code to get the flag. Good luck!"); puts("[+]"); puts("[+] This level is a full Yan85 emulator. You'll have to reason about yancode,"); puts("[+] and the implications of how the emulator interprets it!"); setvbuf(stdout, 0LL, 2, 1uLL); memset(dest, 0, sizeof(dest)); v4 = 0; v5 = 0; v6 = 0; memcpy(dest, &vm_code, (unsigned int)vm_code_length); dest[96] = vm_mem; dest[97] = qword_5328; dest[98] = qword_5330; dest[99] = qword_5338; dest[100] = qword_5340; dest[101] = qword_5348; dest[102] = qword_5350; dest[103] = qword_5358; dest[104] = qword_5360; dest[105] = qword_5368; dest[106] = qword_5370; dest[107] = qword_5378; dest[108] = qword_5380; dest[109] = qword_5388; dest[110] = qword_5390; dest[111] = qword_5398; dest[112] = qword_53A0; dest[113] = qword_53A8; dest[114] = qword_53B0; dest[115] = qword_53B8; dest[116] = qword_53C0; dest[117] = qword_53C8; dest[118] = qword_53D0; dest[119] = qword_53D8; dest[120] = qword_53E0; dest[121] = qword_53E8; dest[122] = qword_53F0; dest[123] = qword_53F8; dest[124] = qword_5400; dest[125] = qword_5408; dest[126] = qword_5410; dest[127] = qword_5418; interpreter_loop(dest); } ``` It copies vm_code into dest after calling memset(make dest 0). - ![image](https://hackmd.io/_uploads/SkApakGKC.png) - As you see, vm_code includes many bytes as the instruction byte for this program. - ![image](https://hackmd.io/_uploads/H1LqAJfK0.png) - vm_mem has the unknown byte, so I check it in pwndbg - ![image](https://hackmd.io/_uploads/Bk4x1xMYC.png) ***interpreter_loop*** ```cpp= void __fastcall __noreturn interpreter_loop(__int64 a1) { unsigned __int8 v1; // al puts("[+] Starting interpreter loop! Good luck!"); while ( 1 ) { v1 = *(_BYTE *)(a1 + 1029); *(_BYTE *)(a1 + 1029) = v1 + 1; interpret_instruction( a1, *(unsigned __int16 *)(a1 + 3LL * v1) | ((unsigned __int64)*(unsigned __int8 *)(a1 + 3LL * v1 + 2) << 16)); } } ``` ***interpret_instruction*** ```cpp= __int64 __fastcall interpret_instruction(unsigned __int8 *a1, __int64 a2) { __int64 result; // rax printf( "[V] a:%#hhx b:%#hhx c:%#hhx d:%#hhx s:%#hhx i:%#hhx f:%#hhx\n", a1[1024], a1[1025], a1[1026], a1[1027], a1[1028], a1[1029], a1[1030]); printf("[I] op:%#hhx arg1:%#hhx arg2:%#hhx\n", (unsigned __int8)a2, BYTE2(a2), BYTE1(a2)); if ( (a2 & 0x40) != 0 ) interpret_imm(a1, a2); if ( (a2 & 0x10) != 0 ) interpret_add(a1, a2); if ( (a2 & 0x80u) != 0LL ) interpret_stk(a1, a2); if ( (a2 & 1) != 0 ) interpret_stm(a1, a2); if ( (a2 & 8) != 0 ) interpret_ldm(a1, a2); if ( (a2 & 0x20) != 0 ) interpret_cmp(a1, a2); if ( (a2 & 2) != 0 ) interpret_jmp(a1, a2); result = a2 & 4; if ( (a2 & 4) != 0 ) return interpret_sys(a1, a2); return result; } ``` It takes the byte instruction to call the respective function. ***The big difference in this level is that the program doesn't give the code.*** I spent many times thinking about the approach to solving this level and writing a script for it. ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level19.py) ```antlr4= [+] v1 @ 0xb6 [+] x | y @ 0x204004 [V] a:0x0 b:0x30 c:0xe d:0x1 s:0x8 i:0xb7 f:0x0 [I] op:0x4 arg1:0x20 arg2:0x40 [*] SYS [s] SYS 0x20 d [s] ... read_memory input: aa [s] ... return value (in register d): 0x2 a1[1024] = 0x0 a1[1025] = 0x30 a1[1026] = 0xe a1[1027] = 0x2 a1[1028] = 0x8 a1[1029] = 0xb7 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x204004 index = a1[1025] = 0x30 a1[index + 768] = a1[816] = input ``` ***Sent byte: aaaa*** ```antlr4= [+] v1 @ 0x6 [+] x | y @ 0x40ff40 [V] a:0x3c b:0x79 c:0xc d:0x95 s:0x6 i:0x7 f:0x0 [I] op:0x40 arg1:0x40 arg2:0xff [*] IMM IMM d = 0xff a1[1024] = 0x3c a1[1025] = 0x79 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x7 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x40ff40 => a1[1027] = 0xff [+] v1 @ 0x7 [+] x | y @ 0x24010 [V] a:0x3c b:0x79 c:0xc d:0xff s:0x6 i:0x8 f:0x0 [I] op:0x10 arg1:0x2 arg2:0x40 [*] ADD [s] ADD a d a1[1024] = 0x3b a1[1025] = 0x79 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x8 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x24010 v2 = a1[1024] = 0x3c v4 = a1[1027] = 0xff a1[1024] = v2 + v4 = 0x3b => a1[1024] += a1[1027] [+] v1 @ 0x8 [+] x | y @ 0x14010 [V] a:0x3b b:0x79 c:0xc d:0xff s:0x6 i:0x9 f:0x0 [I] op:0x10 arg1:0x1 arg2:0x40 [*] ADD [s] ADD b d a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x9 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x14010 v2 = a1[1025] = 0x78 v4 = a1[1027] = 0xff a1[1024] = v2 + v4 = 0x78 => a1[1025] += a1[1027] [+] v1 @ 0x9 [+] x | y @ 0x280 [V] a:0x3b b:0x78 c:0xc d:0xff s:0x6 i:0xa f:0x0 [I] op:0x80 arg1:0x0 arg2:0x2 [*] STK [s] STK N a [s] ... pushing a a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x7 a1[1029] = 0xa a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x000280 a1[2018]++ v5 = a1[1024] = 0x3b index = a1[2018] = 0x7 a1[index + 768] = v5 => a1[775] = a1[1024] = 0x3b [+] v1 @ 0xa [+] x | y @ 0x180 [V] a:0x3b b:0x78 c:0xc d:0xff s:0x7 i:0xb f:0x0 [I] op:0x80 arg1:0x0 arg2:0x1 [*] STK [s] STK N b [s] ... pushing b a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xb a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x000180 a1[2018]++ v5 = a1[1025] = 0x78 index = a1[2018] = 0x8 a1[index + 768] = v5 => a1[776] = a1[1025] = 0x78 [+] v1 @ 0xb [+] x | y @ 0x20208 [V] a:0x3b b:0x78 c:0xc d:0xff s:0x8 i:0xc f:0x0 [I] op:0x8 arg1:0x2 arg2:0x2 [*] LDM [s] LDM a = *a [*] v4 @ 0x3b [*] memory @ 0x0 a1[1024] = 0x0 a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xc a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x020208 v4 = a1[1024] = 0x3b memory = a1[v4 + 768] = a1[827] = 0x0 a1[1024] = memory => a1[1024] = a1[827] [+] v1 @ 0xc [+] x | y @ 0x10108 [V] a:0x0 b:0x78 c:0xc d:0xff s:0x8 i:0xd f:0x0 [I] op:0x8 arg1:0x1 arg2:0x1 [*] LDM [s] LDM b = *b [*] v4 @ 0x78 [*] memory @ 0x45 a1[1024] = 0x0 a1[1025] = 0x45 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xd a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x010108 v4 = a1[1025] = 0x78 memory = a1[v4 + 768] = a1[888] = 0x45 a1[1025] = memory => a1[1025] = a1[888] [+] v1 @ 0xd [+] x | y @ 0x20120 [V] a:0x0 b:0x45 c:0xc d:0xff s:0x8 i:0xe f:0x0 [I] op:0x20 arg1:0x2 arg2:0x1 [*] CMP [s] CMP a = b a1[1024] = 0x0 a1[1025] = 0x45 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xe a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x020120 ``` **compare a1[1024] and a1[1025]** => compare a1[827]( ~ input[12]) and a1[888] = 0x45 ```antlr4= [+] v1 @ 0xe [+] x | y @ 0x10080 [V] a:0x0 b:0x45 c:0xc d:0xff s:0x8 i:0xf f:0x12 [I] op:0x80 arg1:0x1 arg2:0x0 [*] STK [s] STK b N [s] ... popping b a1[1024] = 0x0 a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x7 a1[1029] = 0xf a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x10080 index = a1[1028] = 0x8 memory = a1[index + 768] = a1[776] = 0x78 a1[1025] = memory = 0x78 a1[1028]-- => a1[1025] = a1[776] [+] v1 @ 0xf [+] x | y @ 0x20080 [V] a:0x0 b:0x78 c:0xc d:0xff s:0x7 i:0x10 f:0x12 [I] op:0x80 arg1:0x2 arg2:0x0 [*] STK [s] STK a N [s] ... popping a a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x10 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x20080 index = a1[1028] = 0x7 memory = a1[index + 768] = a1[775] = 0x3b a1[1024] = memory = 0x3b a1[1028]-- => a1[1024] = a1[775] [+] v1 @ 0x10 [+] x | y @ 0x401840 [V] a:0x3b b:0x78 c:0xc d:0xff s:0x6 i:0x11 f:0x12 [I] op:0x40 arg1:0x40 arg2:0x18 [*] IMM IMM d = 0x18 a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0x18 a1[1028] = 0x6 a1[1029] = 0x11 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x401840 => a1[1027] = 0x18 [+] v1 @ 0x11 [+] x | y @ 0x104002 [V] a:0x3b b:0x78 c:0xc d:0x18 s:0x6 i:0x12 f:0x12 [I] op:0x2 arg1:0x10 arg2:0x40 [*] JMP [j] JMP N\x00 d [j] ... TAKEN a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0x18 a1[1028] = 0x6 a1[1029] = 0x18 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x104002 result = a1[1027] = 0x18 a1[1029] = result => a1[1029] = a1[1027] [+] v1 @ 0x18 [+] x | y @ 0x401080 [V] a:0x3b b:0x78 c:0xc d:0x18 s:0x6 i:0x19 f:0x12 [I] op:0x80 arg1:0x40 arg2:0x10 [*] STK [s] STK d c [s] ... pushing c [s] ... popping d a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xc a1[1028] = 0x6 a1[1029] = 0x19 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x401080 pushing: a1[1028]++ v5 = a1[1026] = 0xc index = a1[1028] = 0x7 a1[index + 768] = a1[775] = v5 => a1[775] = a1[1026] popping index = a1[1028] = 0x7 memory = a1[index + 768] = a1[775] a1[1027] = memory a1[1028]-- => a1[1027] = a1[775] => a1[1027] = a1[1026] [+] v1 @ 0x19 [+] x | y @ 0x200080 [V] a:0x3b b:0x78 c:0xc d:0xc s:0x6 i:0x1a f:0x12 [I] op:0x80 arg1:0x20 arg2:0x0 [*] STK [s] STK i N [s] ... popping i a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xc a1[1027] = 0xc a1[1028] = 0x5 a1[1029] = 0x95 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x200080 index = a1[1028] memory = a1[index + 768] = a1[774] = 0x95 a1[1029] = memory => a1[1029] = a1[774] = 0x95 [+] v1 @ 0x95 [+] x | y @ 0x100040 [V] a:0x3b b:0x78 c:0xc d:0xc s:0x5 i:0x96 f:0x12 [I] op:0x40 arg1:0x10 arg2:0x0 [*] IMM IMM c = 0x0 a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0x0 a1[1027] = 0xc a1[1028] = 0x5 a1[1029] = 0x96 a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x100040 => a1[1026] = 0x0 [+] v1 @ 0x96 [+] x | y @ 0x401020 [V] a:0x3b b:0x78 c:0x0 d:0xc s:0x5 i:0x97 f:0x12 [I] op:0x20 arg1:0x40 arg2:0x10 [*] CMP [s] CMP d = c a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0x0 a1[1027] = 0xc a1[1028] = 0x5 a1[1029] = 0x97 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x401020 =>compare a1[1026] and a1[1027] ``` However, this program make` a1[1026] = 0x0` and `a1[1027]` is equal to the old value of `a1[1026]`(force `a1[1026] = 0xc` ~ `IMM c = 0xc`) I don't think what does this compare mean? Thus, I try to pass the first compare and see the result Sent byte: aaaaaaaaaaaE ```antlr4= [+] v1 @ 0x16 [+] x | y @ 0x400640 [V] a:0x3b b:0x78 c:0xb d:0x0 s:0x6 i:0x17 f:0x14 [I] op:0x40 arg1:0x40 arg2:0x6 [*] IMM IMM d = 0x6 a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xb a1[1027] = 0x6 a1[1028] = 0x6 a1[1029] = 0x17 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x400640 => a1[1027] = 0x6 [+] v1 @ 0x17 [+] x | y @ 0x104002 [V] a:0x3b b:0x78 c:0xb d:0x6 s:0x6 i:0x18 f:0x14 [I] op:0x2 arg1:0x10 arg2:0x40 [*] JMP [j] JMP N\x00 d [j] ... TAKEN a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xb a1[1027] = 0x6 a1[1028] = 0x6 a1[1029] = 0x6 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 result = a1[1027] = 0x6 a1[1029] = a1[1027] => a1[1029] = a1[1027] [+] v1 @ 0x6 [+] x | y @ 0x40ff40 [V] a:0x3b b:0x78 c:0xb d:0x6 s:0x6 i:0x7 f:0x14 [I] op:0x40 arg1:0x40 arg2:0xff [*] IMM IMM d = 0xff a1[1024] = 0x3b a1[1025] = 0x78 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x7 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x40ff40 => a1[1027] = 0xff [+] v1 @ 0x7 [+] x | y @ 0x24010 [V] a:0x3b b:0x78 c:0xb d:0xff s:0x6 i:0x8 f:0x14 [I] op:0x10 arg1:0x2 arg2:0x40 [*] ADD [s] ADD a d a1[1024] = 0x3a a1[1025] = 0x78 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x8 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x24010 v2 = a1[1024] = 0x3a v4 = a1[1027] = 0xff a1[1024] = v2 + v4 => a1[1024] += a1[1027] [+] v1 @ 0x8 [+] x | y @ 0x14010 [V] a:0x3a b:0x78 c:0xb d:0xff s:0x6 i:0x9 f:0x14 [I] op:0x10 arg1:0x1 arg2:0x40 [*] ADD [s] ADD b d a1[1024] = 0x3a a1[1025] = 0x77 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x6 a1[1029] = 0x9 a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x14010 v2 = a1[1025] = 0x3a v4 = a1[1027] = 0xff a1[1025] = v2 + v4 => a1[1025] += a1[1027] [+] v1 @ 0x9 [+] x | y @ 0x280 [V] a:0x3a b:0x77 c:0xb d:0xff s:0x6 i:0xa f:0x14 [I] op:0x80 arg1:0x0 arg2:0x2 [*] STK [s] STK N a [s] ... pushing a a1[1024] = 0x3a a1[1025] = 0x77 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x7 a1[1029] = 0xa a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x000280 a1[1028]++ v5 = a1[1024] = 0x3a index = a1[1028] a1[index + 768] = a1[775] = v5 => a1[775] = a1[1024] [+] v1 @ 0xa [+] x | y @ 0x180 [V] a:0x3a b:0x77 c:0xb d:0xff s:0x7 i:0xb f:0x14 [I] op:0x80 arg1:0x0 arg2:0x1 [*] STK [s] STK N b [s] ... pushing b a1[1024] = 0x3a a1[1025] = 0x77 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xb a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x000180 a1[1028]++ v5 = a1[1025] = 0x77 index = a1[1028] a1[index + 768] = a1[776] = v5 => a1[776] = a1[1024] [+] v1 @ 0xb [+] x | y @ 0x20208 [V] a:0x3a b:0x77 c:0xb d:0xff s:0x8 i:0xc f:0x14 [I] op:0x8 arg1:0x2 arg2:0x2 [*] LDM [s] LDM a = *a [*] v4 @ 0x3a [*] memory @ 0x61 a1[1024] = 0x61 a1[1025] = 0x77 a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xc a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x20208 v4 = a1[1024] = 0x3a memory = a1[v4 + 768]= a1[826] a1[1024] = memory => a1[1024] = a1[826] [+] v1 @ 0xc [+] x | y @ 0x10108 [V] a:0x61 b:0x77 c:0xb d:0xff s:0x8 i:0xd f:0x14 [I] op:0x8 arg1:0x1 arg2:0x1 [*] LDM [s] LDM b = *b [*] v4 @ 0x77 [*] memory @ 0xbb a1[1024] = 0x61 a1[1025] = 0xbb a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xd a1[1030] = 0x14 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 0x10108 v4 = a1[1025] = 0x77 memory = a1[v4 + 768] = a1[887] => a1[1025] = a1[888] [+] v1 @ 0xd [+] x | y @ 0x20120 [V] a:0x61 b:0xbb c:0xb d:0xff s:0x8 i:0xe f:0x14 [I] op:0x20 arg1:0x2 arg2:0x1 [*] CMP [s] CMP a = b a1[1024] = 0x61 a1[1025] = 0xbb a1[1026] = 0xb a1[1027] = 0xff a1[1028] = 0x8 a1[1029] = 0xe a1[1030] = 0x12 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 compare a1[1024] and a1[1025] <=> compare a1[826] and a1[887] ``` Here, I will conclude my supposition and guess the work of compare. - First, it will compare the index 12 of my input(a1[827]) with the respective byte(a1[888]) - Next, it compares something couple of value(I don't know what does this mean? I guess it will make the instruction for the next compare) - Then, it compares the similar couple, but index subtract 1 (a1[826] and a1[887]) - And, the next unknown compare happens - This loop is has the rule, I follow with this and have the license key. ## 19.1 ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/level19_1.py) # Level 20 ## 20.0 In this level, vm_mem is not empty. ![image](https://hackmd.io/_uploads/By7UdmtYA.png) ### [Script DEBUG](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/src/level20_DEBUG.py) ```antlr4= [+] v1 @ 0xdc [+] x | y @ 0x18004 [V] a:0x0 b:0x30 c:0x22 d:0x5 s:0x3 i:0xdd f:0x0 [I] op:0x80 arg1:0x4 arg2:0x1 [*] SYS [s] SYS 0x4 d [s] ... read_memory input: aaaaaaaaaaaaaaaaaaaaaaaaaaaa [s] ... return value (in register d): 0x1c a1[1024] = 0x0 a1[1025] = 0x30 a1[1026] = 0x22 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xdd a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 ``` input at index a1[768 + 0x30] ~ a1[816] ```antlr4= [+] v1 @ 0x3 [+] x | y @ 0xff0801 [V] a:0x4c b:0xb8 c:0x1c d:0xc6 s:0x1 i:0x4 f:0x0 [I] op:0x8 arg1:0x1 arg2:0xff [*] IMM IMM d = 0xff a1[1024] = 0x4c a1[1025] = 0xb8 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x1 a1[1029] = 0x4 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 => a1[1027] = 0xff [+] v1 @ 0x4 [+] x | y @ 0x14010 [V] a:0x4c b:0xb8 c:0x1c d:0xff s:0x1 i:0x5 f:0x0 [I] op:0x40 arg1:0x10 arg2:0x1 [*] ADD [s] ADD a d a1[1024] = 0x4b a1[1025] = 0xb8 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x1 a1[1029] = 0x5 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v2 = a1[1024] = 0x4b v4 = a1[1027] = 0xff a1[1024] = v2 + v4 => a1[1024] += a1[1027] [+] v1 @ 0x5 [+] x | y @ 0x14002 [V] a:0x4b b:0xb8 c:0x1c d:0xff s:0x1 i:0x6 f:0x0 [I] op:0x40 arg1:0x2 arg2:0x1 [*] ADD [s] ADD b d a1[1024] = 0x4b a1[1025] = 0xb7 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x1 a1[1029] = 0x6 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v2 = a1[1025] = 0xb7 v4 = a1[1027] = 0xff a1[1025] = v2 + v4 => a1[1025] += a1[1027] [+] v1 @ 0x6 [+] x | y @ 0x100200 [V] a:0x4b b:0xb7 c:0x1c d:0xff s:0x1 i:0x7 f:0x0 [I] op:0x2 arg1:0x0 arg2:0x10 [*] STK [s] STK N a [s] ... pushing a a1[1024] = 0x4b a1[1025] = 0xb7 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x2 a1[1029] = 0x7 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 a1[1028]++ v5 = a1[1024] = 0x4b index = a1[1028] a1[index + 768] = v5 => a1[770] = 0x4b [+] v1 @ 0x7 [+] x | y @ 0x20200 [V] a:0x4b b:0xb7 c:0x1c d:0xff s:0x2 i:0x8 f:0x0 [I] op:0x2 arg1:0x0 arg2:0x2 [*] STK [s] STK N b [s] ... pushing b a1[1024] = 0x4b a1[1025] = 0xb7 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x3 a1[1029] = 0x8 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 a1[1028]++ v5 = a1[1025] = 0xb7 index = a1[1028] a1[index + 768] = v5 => a1[771] = 0x4b [+] v1 @ 0x8 [+] x | y @ 0x102010 [V] a:0x4b b:0xb7 c:0x1c d:0xff s:0x3 i:0x9 f:0x0 [I] op:0x20 arg1:0x10 arg2:0x10 [*] LDM [s] LDM a = *a [*] v4 @ 0x4b [*] memory @ 0x7 a1[1024] = 0x7 a1[1025] = 0xb7 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x3 a1[1029] = 0x9 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v4 = a1[1024] = 0x4b memory = a1[768 +v4] = a1[843] a1[1024] = memory => a1[1024] = a1[843] [+] v1 @ 0x9 [+] x | y @ 0x22002 [V] a:0x7 b:0xb7 c:0x1c d:0xff s:0x3 i:0xa f:0x0 [I] op:0x20 arg1:0x2 arg2:0x2 [*] LDM [s] LDM b = *b [*] v4 @ 0xb7 [*] memory @ 0x62 a1[1024] = 0x7 a1[1025] = 0x62 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x3 a1[1029] = 0xa a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v4 = a1[1025] = 0xb7 memory = a1[768 +v4] = a1[951] a1[1024] = memory => a1[1025] = a1[951] [+] v1 @ 0xa [+] x | y @ 0x20410 [V] a:0x7 b:0x62 c:0x1c d:0xff s:0x3 i:0xb f:0x0 [I] op:0x4 arg1:0x10 arg2:0x2 [*] CMP [s] CMP a = b a1[1024] = 0x7 a1[1025] = 0x62 a1[1026] = 0x1c a1[1027] = 0xff a1[1028] = 0x3 a1[1029] = 0xb a1[1030] = 0x3 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 compare a1[1024] and a1[1025] <=> compare a1[843] and a1[951] ``` In this level, I can use the same trick to solve this challenge as in the previous level. However, in the previous challenge, I knew that my input remains unchanged and is compared with the license key, so to solve the problem quickly, I write some code to find each key ╰(*°▽°*)╯. Now, I can also calculate the distance between my input and the value of my input after changing it and the license key I get; and I can solve this successfully, but I don't do this; I'm legit (●'◡'●). I get one of the changes my input, and the others are the same. ```antlr4= [+] v1 @ 0xa1 [+] x | y @ 0x4b0810 [V] a:0x4a b:0x36 c:0xd5 d:0x1c s:0x3 i:0xa2 f:0x0 [I] op:0x8 arg1:0x10 arg2:0x4b [*] IMM IMM a = 0x4b a1[1024] = 0x4b a1[1025] = 0x36 a1[1026] = 0xd5 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xa2 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 => a1[1024] = 0x4b [+] v1 @ 0xa2 [+] x | y @ 0xa60840 [V] a:0x4b b:0x36 c:0xd5 d:0x1c s:0x3 i:0xa3 f:0x0 [I] op:0x8 arg1:0x40 arg2:0xa6 [*] IMM IMM c = 0xa6 a1[1024] = 0x4b a1[1025] = 0x36 a1[1026] = 0xa6 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xa3 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 => a1[1026] = 0xa6 [+] v1 @ 0xa3 [+] x | y @ 0x102002 [V] a:0x4b b:0x36 c:0xa6 d:0x1c s:0x3 i:0xa4 f:0x0 [I] op:0x20 arg1:0x2 arg2:0x10 [*] LDM [s] LDM b = *a [*] v4 @ 0x4b [*] memory @ 0x61 a1[1024] = 0x4b a1[1025] = 0x61 a1[1026] = 0xa6 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xa4 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v4 = a1[1024] = 0x4b memory = a1[768 + v4] = a1[843] a1[1025] = memory => a1[1025] = a1[843] [+] v1 @ 0xa4 [+] x | y @ 0x404002 [V] a:0x4b b:0x61 c:0xa6 d:0x1c s:0x3 i:0xa5 f:0x0 [I] op:0x40 arg1:0x2 arg2:0x40 [*] ADD [s] ADD b c a1[1024] = 0x4b a1[1025] = 0x7 a1[1026] = 0xa6 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xa5 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v2 = a1[1025] = 0x61 v4 = a1[1026] = 0xa6 a1[1025] = v2 + v4 => a1[1025] = a1[1025] + a1[1026] [+] v1 @ 0xa5 [+] x | y @ 0x21010 [V] a:0x4b b:0x7 c:0xa6 d:0x1c s:0x3 i:0xa6 f:0x0 [I] op:0x10 arg1:0x10 arg2:0x2 [*] STM [s] STM *a = b a1[1024] = 0x4b a1[1025] = 0x7 a1[1026] = 0xa6 a1[1027] = 0x1c a1[1028] = 0x3 a1[1029] = 0xa6 a1[1030] = 0x0 a1[1031] = 0x0 a1[1032] = 0x0 a1[1033] = 0x0 v2 = a1[1025] = 0x7 v4 = a1[1024] = 0x4b index = v4 = 0x4b a1[index + 768] = v2 => a1[843] = a1[1025] ``` IMM a = 0x4b (get index)→ IMM c = 0xa6 (get value to add ~ distance) → [s] LDM b = *a (init value at index 0x4b) → [s] ADD b c (add distance) → [s] STM *a = b (store value after changes to old index) ```python value_add = [0x48, 0x9c, 0xa , 0x9a , 0x3f , 0x41 ,0x93, 0x94 ,0xac , 0xd4,0x72 ,0xdd ,0x5a ,0x7, 0xc6, 0x90,0xa2,0xc0 ,0xdd,0x37, 0xa4,0x4,0x22, 0x9c, 0xad, 0xc2, 0xd5, 0xa6] ``` ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/src/level20.py) ## 20.1 ### [Script DEBUG](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/src/level20_1_DEBUG.py) ### [Script](https://github.com/BabyBroder/pwncollege/blob/Program-Security/Reverse-Engineering/src/level20_1.py)