; OPCODE <00 00>
00DEA4FA pop dword ptr fs:[0000h]
00DEA500 add esp,4
00DEA503 popad
00DEA7BF mov eax,dword ptr [esi+2]
; get a long
00DEAA79 xor eax,37195411h
; decrypt it
00DEAD23 push eax
; push on stack
00DEAFEA mov eax,0FFFFFF3Fh
00DEB299 not eax
; C0
00DEB553 shr eax,5
; 6: instruction length
00DEB829 lea esi,[esi+eax]
; update pointer
...
; OPCODE <00 01>
00DEC36A pop dword ptr fs:[0000h]
00DEC370 add esp,4
00DEC373 popad
00DEC633 mov eax,dword ptr [esi+2]
; get a long
00DEC8CD add eax,0ADD01337h
; decrypt it
00DECB8A push eax
; push on stack
00DECE37 mov eax,0FFFFF5D1h
00DED113 not eax
; 0A2E
00DED3BB xor eax,0A28h
; 6: instruction length
00DED680 lea esi,[esi+eax]
; update pointer
...
; OPCODE <00 02>
00E173B7 pop dword ptr fs:[0000h]
00E173BD add esp,4
00E173C0 popad
00E1766E movzx eax,byte ptr [esi+2]
; get a byte
00E17920 xor eax,47h
; decode the global index
00E17BF4 mov eax,dword ptr [eax*4+0DE8736h]
; global[index]
00E17EB7 push eax
; push on stack
00E18144 mov ebx,0Ah
00E18149 xor ebx,9
; 3: instruction length
00E1814C add esi,ebx
; update pointer
...
; OPCODE <00 03>
00E1B0C1 pop dword ptr fs:[0000h]
00E1B0C7 add esp,4
00E1B0CA popad
00E1B372 movzx eax,byte ptr [esi+2]
; get a byte
00E1B376 xor eax,66h
; decode the global index
00E1B64A pop dword ptr [eax*4+0DE8736h]
; pop to global[index]
00E1B8CF add esi,4
; update pointer
00E1B8D2 dec esi
; += 3: instruction length
...
; OPCODE<00 04>
00E14CC1 pop dword ptr fs:[0000h]
00E14CC7 add esp,4
00E14CCA popad
00E14F95 movzx eax,byte ptr [esi+2]
; get a byte
00E14F99 xor eax,45h
; decrypt it
00E1524C add esp,eax
; inc ESP by those bytes
00E1524E add esi,3
; update pointer
...
; OPCODE <01 03>
00DF74EF pop dword ptr fs:[0000h]
00DF74F5 add esp,4
00DF74F8 popad
00DF7787 movzx eax,byte ptr [esi+2]
; get srcidx
00DF7A49 mov eax,dword ptr [eax*4+0DE8736h]
; global[srcidx]
00DF7CF9 movzx ecx,byte ptr [esi+3]
; get xortype
00DF7FC4 jmp dword ptr [ecx*4+0E1B9E9h]
; xortype == 0
00DF8266 movzx ecx,byte ptr [esi+4]
; get dstidx
00DF8532 mov ecx,dword ptr [ecx*4+0DE8736h]
; global[dstidx]
00DF87CF xor byte ptr [ecx],al
; byte xor
00DF8A6F add esi,5 ;
+= instruction length
...
; xortype == 1
00DF92E8 movzx ecx,byte ptr [esi+4]
; get dstidx
00DF9593 mov ecx,dword ptr [ecx*4+0DE8736h]
; global[dstidx]
00DF9848 xor word ptr [ecx],ax
; word xor
00DF9AE6 add esi,5 ;
+= instruction length
...
; xortype == 2
00DFA5F7 movzx ecx,byte ptr [esi+4]
; get dstidx
00DFA8C1 mov ecx,dword ptr [ecx*4+0DE8736h]
; global[dstidx]
00DFAE0F xor dword ptr [ecx],eax
; long xor
00DFB0EE add esi,5 ;
+= instruction length
...
; OPCODE <01 04>
00E181A6 pop dword ptr fs:[0000h]
00E181AC add esp,4
00E181AF popad
00E18478 movzx eax,byte ptr [esi+2]
; idx
00E18721 sub eax,3
; idx -= 3
00E189C0 mov ebx,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E18C5F mov edi,dword ptr [esi+3]
; get constant
00E18F2C add ebx,edi
; global[idx]+constant
; update NotZero Flag
00E18F2E jne 00E1921A
00E19211 and dword ptr ds:[0DE874Ah],0
00E19218 jmp 00E19224
; E19502
00E1921A mov dword ptr ds:[0DE874Ah],1
00E19502 mov dword ptr [eax*4+0DE8736h],ebx
; update global[idx]
00E197AA add esi,7
; += instruction length
...
; OPCODE <01 05>
00E1A05B pop dword ptr fs:[0000h]
00E1A061 add esp,4
00E1A064 popad
00E1A2DA movzx eax,byte ptr [esi+2]
; idx
00E1A582 sub eax,2
; idx -= 2
00E1A852 mov ebx,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E1AB03 mov edi,dword ptr [esi+3]
; get constant
00E1ADD3 sub ebx,edi
; global[idx]-constant
; update NotZero Flag
00E1ADD5 jne 00E1ADE0
00E1ADD7 and dword ptr ds:[0DE874Ah],0
00E1ADDE jmp 00E1ADEA
; E1B05F
00E1ADE0 mov dword ptr ds:[0DE874Ah],1
00E1B05F mov dword ptr [eax*4+0DE8736h],ebx
; update global[idx]
00E1B066 add esi,7
; update pointer
...
; OPCODE <01 06>
00E1226D pop dword ptr fs:[0000h]
00E12273 add esp,4
00E12276 popad
00E12526 movzx eax,byte ptr [esi+2]
; idx
00E1252A sub eax,5
; idx -= 5
00E127B4 mov ebx,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E12A80 mov edi,dword ptr [esi+3]
; get constant
00E12D2E and ebx,edi
; global[idx]-constant
; update NotZero Flag
00E12D30 jne 00E12D3E
00E12D32 and dword ptr ds:[0DE874Ah],0
00E12D39 jmp 00E12FF9
; E132EE
00E12FEF mov dword ptr ds:[0DE874Ah],1
00E132EE mov dword ptr [eax*4+0DE8736h],ebx
; update global[idx]
00E132F5 add esi,7
; update pointer
...
; OPCODE <01 07>
00E14128 pop dword ptr fs:[0000h]
00E1412E add esp,4
00E14131 popad
00E143F8 movzx eax,byte ptr [esi+2]
; idx
00E143FC sub eax,4
; idx -= 5
00E146AE mov ebx,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E146B5 mov edi,dword ptr [esi+3]
; get constant
00E14974 or ebx,edi
; global[idx]|constant
; update NotZero Flag
00E14976 jne 00E14981
00E14978 and dword ptr ds:[0DE874Ah],0
00E1497F jmp 00E1498B
00E14981 mov dword ptr ds:[0DE874Ah],1
00E1498B mov dword ptr [eax*4+0DE8736h],ebx
; update global[idx]
00E14C66 add esi,7
; update pointer
...
; OPCODE <01 08>
00E016ED pop dword ptr fs:[0000h]
00E016F3 add esp,4
00E016F6 popad
00E019C1 movzx eax,byte ptr [esi+2]
; idx
00E01C73 mov ebx,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E01F36 mov edi,dword ptr [esi+3]
; get constant
00E021B7 xor ebx,edi
; global[idx]^constant
; update NotZero Flag
00E021B9 jne 00E02732
00E0247E and dword ptr ds:[0DE874Ah],0
00E0272D jmp 00E02C74
00E029B3 mov dword ptr ds:[0DE874Ah],1
00E02C74 mov dword ptr [eax*4+0DE8736h],ebx
; update global[idx]
00E02F55 mov edi,0E00h
00E02F5A shr edi,9
; 7: instruction length
00E031FB add esi,edi
; update pointer
...
; OPCODE <01 09>
00E05353 pop dword ptr fs:[0000h]
00E05359 add esp,4
00E0535C popad
00E055EA movzx eax,byte ptr [esi+2]
; firstidx
00E058B1 dec eax
; firstidx-1
00E05B4B mov ebx,dword ptr [eax*4+0DE8736h]
; get global[firstidx-1]
00E05DFF movzx eax,byte ptr [esi+3]
; secondidx
00E060DF sub eax,3
; secondidx-3
00E0636D mov edi,dword ptr [eax*4+0DE8736h]
; global[secondidx-3]
00E06610 add edi,ebx
; sum both globals
; update NotZero Flag
00E06612 jne 00E06B54
; E06E08
00E068AE and dword ptr ds:[0DE874Ah],0
00E06B4F jmp 00E06E12
; E070E0
00E06E08 mov dword ptr ds:[0DE874Ah],1
00E070E0 mov dword ptr [eax*4+0DE8736h],edi
; update global[secondidx-3]
00E070E7 add esi,4
; update pointer
...
; OPCODE <01 0A>
00DFB948 pop dword ptr fs:[0000h]
00DFB94E add esp,4
00DFB951 popad
00DFBBE6 movzx eax,byte ptr [esi+2]
; firstidx
00DFBEAA sub eax,2
; firstidx-2
00DFBEAD mov ebx,dword ptr [eax*4+0DE8736h]
; get global[firstidx-2]
00DFC166 movzx eax,byte ptr [esi+3]
; secondidx
00DFC41D dec eax
; secondidx-1
00DFC6C7 mov edi,dword ptr [eax*4+0DE8736h]
; get global[secondidx-1]
00DFC98A cmp edi,ebx
; second CMP first
; update NotZero Flag
00DFC98C jne 00DFCEFD
00DFCC35 and dword ptr ds:[0DE874Ah],0
00DFCEF8 jmp 00DFD18C
00DFCEFD mov dword ptr ds:[0DE874Ah],1
; assign global[firstidx-2] to global[secondidx-1]
00DFD18C mov dword ptr [eax*4+0DE8736h],ebx
00DFD43F add esi,4
; update pointer
...
; OPCODE <02 00>
00DEE16F pop dword ptr fs:[0000h]
00DEE175 add esp,4
00DEE401 popad
00DEE402 push dword ptr ds:[0E1BC73h]
; encoded exit address
00DEE684 xor dword ptr [esp],48415830h
; DE872F
00DEE946 ret
; go to exit snippet
; OPCODE <02 01>
00DEE947 pop dword ptr fs:[0000h]
00DEE94D add esp,4
00DEE950 popad
00DEEC12 mov eax,dword ptr [esi+2]
; get a long
00DEEEC7 add eax,0FEA731DEh
; decode it
00DEF171 mov eax,dword ptr [eax+2]
00DEF411 mov eax,dword ptr [eax]
; external address
; make the address relative, to be put in the following call
00DEF413 mov edi,0DEF94Eh
00DEF418 sub eax,edi
00DEF69D sub eax,4
00DEF94C stos dword ptr [edi]
; put address to DEF94E
00DEF94D call ...
; call the API
; store the result in global[0]
00DEFC14 mov [00DE8736],eax
; update NotZero Flag
00DEFEBA test eax,eax
00DEFEBC jne 00DF09CA
; DF0C4B
00DF0150 and dword ptr ds:[0DE874Ah],0
; go to DF0C55 -> DF0F24
00DF0443 mov edi,0DEE6B3h
00DF0448 push edi
00DF0715 add dword ptr [esp],25A2h
; DF0C55
00DF09C9 ret
; go to DF0C55
00DF0C4B mov dword ptr ds:[0DE874Ah],1
00DF0F24 add esi,6
; instruction length
...
; OPCODE <02 02>
00DFDCA3 pop dword ptr fs:[0000h]
00DFDCA9 add esp,4
00DFDCAC popad
00DFDCAD mov eax,dword ptr [esi+2]
; get encoded long
00DFDF5E add eax,0AEFDED04h
00DFE20E movzx edi,byte ptr [esi+6]
; idx
00DFE4DC mov dword ptr [edi*4+0DE8736h],eax
00DFE4E3 add esi,7
; update pointer
...
; OPCODE <02 03>
00E09AB5 pop dword ptr fs:[0000h]
00E09ABB add esp,4
00E09ABE popad
00E09D76 movzx eax,byte ptr [esi+2]
; idx
00E0A03E dec dword ptr [eax*4+0DE8736h]
; update NotZero Flag
00E0A045 jne 00E0A811
00E0A2E4 and dword ptr ds:[0DE874Ah],0
00E0A587 jmp 00E0AD8F
00E0AACC mov dword ptr ds:[0DE874Ah],1
00E0AD8F add esi,3
; update pointer
...
; OPCODE <02 04>
00E0D4BC pop dword ptr fs:[0000h]
00E0D4C2 add esp,4
00E0D4C5 popad
00E0D4C6 movzx eax,byte ptr [esi+2]
; idx
00E0D76F inc dword ptr [eax*4+0DE8736h]
; update NotZero Flag
00E0D776 jne 00E0DCF2
; E0DF7A
00E0DA49 and dword ptr ds:[0DE874Ah],0
00E0DCED jmp 00E0E229
00E0DF7A mov dword ptr ds:[0DE874Ah],1 ; set NZflag
00E0E229 add esi,3
; update pointer
...
; OPCODE <02 05>
00E11477 pop dword ptr fs:[0000h]
00E1147D add esp,4
00E11480 popad
00E11726 movzx eax,byte ptr [esi+2]
; idx
00E119CF and dword ptr [eax*4+0DE8736h],0
00E11C70 and dword ptr ds:[0DE874Ah],0
; clear NotZero Flag
00E11C77 add esi,3
; update pointer
...
; OPCODE <02 06>
00E15B11 pop dword ptr fs:[0000h]
00E15B17 add esp,4
00E15B1A popad
00E15DBC movzx eax,byte ptr [esi+2]
; idx
00E16049 mov edi,dword ptr ds:[0DE8736h]
; get value from global[0]
00E162EE movzx ecx,word ptr [esi+3]
; get count
00E1658B repne scas byte ptr [edi]
00E16843 test ecx,ecx
00E16845 je 00E17352
; found
00E16AF2 mov dword ptr ds:[0DE8736h],edi
; store new ptr in result[0]
; go to E1735C
00E16DCB push 0E0DD08h
00E1707F add dword ptr [esp],9654h
; E1735C
00E17351 ret
; not found
00E17352 mov dword ptr ds:[0DE874Ah],0
; clear NZflag
00E1735C add esi,5
; update pointer
...
; OPCODE <02 07>
00E1B92B pop dword ptr fs:[0000h]
00E1B931 add esp,4
00E1B934 popad
00E1B935 int 3
; break
00E1B936 add esi,2
; update pointer (only 2 bytes)
...
; OPCODE <02 08>
00E0E816 pop dword ptr fs:[0000h]
00E0E81C add esp,4
00E0E81F popad
00E0EAE9 movzx eax,byte ptr [esi+2]
; srcidx
00E0ED84 mov eax,dword ptr [eax*4+0DE8736h]
00E0F030 mov eax,dword ptr [eax]
; dereference
00E0F032 movzx edi,byte ptr [esi+3]
; dstidx
00E0F2E0 mov dword ptr [edi*4+0DE8736h],eax
; assign
00E0F2E7 add esi,4
; update pointer
...
;
OPCODE <02 09>
00E0C6C9 pop dword ptr fs:[0000h]
00E0C6CF add esp,4
00E0C6D2 popad
00E0C6D3 movzx eax,byte ptr [esi+2]
; idx
00E0C99A mov eax,dword ptr [eax*4+0DE8736h]
; get global[idx]
00E0CC35 bswap eax
; BUG: do not save back
00E0CF0A add esi,3
; update pointer
...
; OPCODE <02 0A>
00E0B5E7 pop dword ptr fs:[0000h]
00E0B5ED add esp,4
00E0B5F0 popad
00E0B8C1 movzx eax,byte ptr [esi+2]
; srcidx
00E0B8C5 mov eax,dword ptr [eax*4+0DE8736h]
00E0BB76 movzx eax,byte ptr [eax]
; dereference
00E0BE33 movzx edi,byte ptr [esi+3]
; dstidx
00E0C0C0 mov dword ptr [edi*4+0DE8736h],eax
; assign
00E0C3C4 add esi,4
; update pointer
...
; OPCODE <02 0B>
00E03D6A pop dword ptr fs:[0000h]
00E03D70 add esp,4
00E03D73 popad
00E0402D movzx eax,byte ptr [esi+2]
; srcidx
00E042E6 mov eax,dword ptr [eax*4+0DE8736h]
00E04588 movzx eax,word ptr [eax]
; dereference
00E04823 movzx edi,byte ptr [esi+3]
; dstidx
00E04ACD mov dword ptr [edi*4+0DE8736h],eax
; assign
00E04D5F add esi,4
; update pointer
...
;
OPCODE <03 00>
00DFEFDC pop dword ptr fs:[0000h]
00DFEFE2 add esp,4
00DFEFE5 popad
00DFF2A3 mov eax,dword ptr [esp]
; first value
00DFF51B cmp eax,dword ptr [esp+4]
; cmp second value
00DFF51F jne 00E005E5
; E008A4
; equal
00DFF80F add esp,8
; clean stack
00DFFAC1 mov esi,dword ptr [esi+2]
; address
00DFFD4A sub esi,31337h ;
address -= 31337
00DFFFF6 movzx eax,byte ptr [esi]
; first byte from new flow
...
; not equal
00E008A4 mov eax,0FFFFFFF9h
00E00B6A not eax
; 6
00E00B6C add esi,eax
; update pointer
00E00E27 add esp,8
; clear the stack
...
; OPCODE <04 00>
00E034FD pop dword ptr fs:[0000h]
00E03503 add esp,4
00E03506 popad
; modify the pointer
00E037D6 mov esi,dword ptr [esi+2]
; address
00E03A61 add esi,0DEADEADh
; address+DEADEAD
...
; OPCODE <04 01>
00E07989 pop dword ptr fs:[0000h]
00E0798F add esp,4
00E07992 popad
00E07C49 mov eax,[0DE874Ah]
; NotZero Flag
00E07EF4 test eax,eax
00E07EF6 jne 00E08A51
; jump to given address
; continue in sequence
00E081AF add esi,6
; update pointer
...
; jump to given address
00E08CFE mov esi,dword ptr [esi+2]
; address
00E08FC2 lea esi,[esi+0E1BA3Eh]
; address+E1BA3E
...
; OPCODE <04 02>
00E0F8A7 pop dword ptr fs:[0000h]
00E0F8AD add esp,4
00E0F8B0 popad
00E0FB4D mov eax,[00DE874A]
; get NotZero Flag
00E0FE17 test eax,eax
00E0FE19 je 00E1096C
; jump to given address
; continue in sequence
00E0FE1F add esi,6
; update pointer
...
; jump to given address
00E1096C mov esi,dword ptr [esi+2]
; address
00E10BE5 lea esi,[esi+0E1BA41h]
; address+E1BA41
...
;
OPCODE <05 00>
00E13604 pop dword ptr fs:[0000h]
00E1360A add esp,4
00E1360D popad
00E1389E mov eax,dword ptr [esi+2]
; address
00E13B63 lea edi,[esi+6]
; return address
00E13B66 push edi
; push the return address
00E13E36 mov esi,eax
; set the pointer to the new address
...
; OPCODE <05 01>
00E15554 pop dword ptr fs:[0000h]
00E1555A add esp,4
00E1555D popad
; retrieve the return address from the stack
00E1555E pop esi
...
At this point, the biggest part of our job is over.
We have mentioned before the opcode
<02 07>: as we have seen above,
it simply perform an Interrupt 3. This means that we can patch in any point
the opcodes flow with the couple of bytes 02 07, and our debugger will break
at that point: we are now free to examine the globals, or to restart in
single stepping mode.
The only caution we must take is to replace back the two opcodes overwritten
by 02 07, before restarting.
We can finally analyze the opcodes. with the opcodes table in front of us!
Let's start, founding the first 4 characters of the password!
;
; E1BA3D: coded area starts here
; globals[0-5] at DE8736, NotZero Flag at DE874A
;
; decrypt first the opcodes from E1BA65 to E1BC73
E1BA3D 02 02 5102150A 03
; global[3] <- encoded 20E (opcodes length)
E1BA44 00 01 5311A72E
; push constant (ptr E1BA65)
E1BA4A 00 03 66
; pop at global[66^66]
E1BA4D 02 02 5102134F 02
; put 00000053 in global[2]: xor value
; decryption loop
E1BA54 01 03 02 00 00
; *global[0] ^= (BYTE)global[2]
E1BA59 02 04 00
; bump global[0]
E1BA5C 02 03 03
; dec global[3] (length)
E1BA5F 04 01 00000016
; jnz E1BA3E+16h (E1BA54)
; here start the decrypted code
; (shown already decrypted)
E1BA65 02 02 ADCA212D 01
; 5CC80E31 to global[1]
E1BA6C 02 01 0236DE2F
; call GetCommandLineA, store the result in global[0]
; after the scan, global[0] has the pointer to the password:
; c0 c1 c2 c3 c4 c5 c6 c7 c8
E1BA72 02 06 20 0255
; scan for <20> in *(result[0]) for at most 0255h bytes
E1BA77 04 02 0000012E
; jz (not found) E1BA41+12E=E1BB6F (ko)
E1BA7D 02 08 00 02
; global[2] <- *global[0] = c3 c2 c1 c0
; check c0 c1 c2 c3
E1BA81 01 04 05 1D9BDC45
; global[5-3] += 1D9BDC45 = c3c2c1c0 + 1D9BDC45
E1BA88 01 04 04 74519745
; global[4-3] += 74519745 = D119A576
E1BA8F 01 05 04 AD45DFE2
; global[4-2] -= AD45DFE2 = c3c2c1c0 - 8FAA039D
E1BA96 01 04 04 DEADBEEF
; global[4-3] += DEADBEEF = AFC76465
01 04 05 68656C6C
; global[5-3] += 68656C6C = c3c2c1c0 - 27449731
01 05 03 17854165
; global[3-2] -= 17854165 = 98422300
01 05 04 41776169
; global[4-2] -= 41776169 = c3c2c1c0 - 68BBF89A
01 04 04 73686F77
; global[4-3] += 73686F77 = 0BAA9277
01 04 05 69747320
; global[5-3] += 69747320 = c3c2c1c0 + 00B87A86
01 05 03 206E6F20
; global[3-2] -= 206E6F20 = EB3C2357
01 04 05 64726976
; global[5-3] += 64726976 = c3c2c1c0 + 652AE3FC
01 04 04 6D657263
; global[4-3] += 6D657263 = 58A195BA
01 05 04 6E757473
; global[4-2] -= 6E757473 = c3c2c1c0 - 094A9077
01 05 03 79212121
; global[3-2] -= 79212121 = DF807499
01 05 04 65683F21
; global[4-2] -= 65683F21 = c3c2c1c0 - 6EB2CF98
01 06 07 DFFFFFFF
; global[7-5] &= DFFFFFFF
; c3c2c1c0-6EB2CF98(global[2]) must equal DF807499(global[1]
; this means c3c2c1c0 = DF807499+6EB2CF98 = 4E334431 ("n3D1")
00 02 45
; push global[45^47(2)]
00 02 46
; push global[1]
03 00 00E4CE3D
; cmp and jmp to E1BB06 if same
; not the same
02 05 03
; clear global[3] and NZflag
04 02 0000012E
; jz E1BB6F ko
; skip c0 c1 c2 c3, already checked
; password ptr += 4
E1BB06 02 04 00
; bump global[0], ptr to password
01 04 03 00000002
; global[3-3] += 2
02 04 00
; bump global[0] long
The following instructions will check two other characters of the password,
c4 and c5. To be more exact, the two bytes c4 and c5 are xored with two
bytes inside the flow of the opcodes: if the result is not correct, it is
very easy that the program will crash. We note here that the solution
can be more than one.
The original bytes,
47 42 (03), xored with c4 c5, must give a valid
instruction having 3 bytes as length. From all the possible 3-bytes
solutions, we must exclude the push/pop instructions 00 02 03 and 00 03 03)
to avoid stack unpairing. The other possible solutions are 02 03 03 (DEC
global[3]), 02 04 03 (INC global[3]), 02 05 03 (CLEAR global[3]) and
02 09 03 (BSWAP global[3]). They are all valid, since the content of
global[3], which will be pushed as second argument of
printf, is
meaningless.
In fact, printf() requires only one argument when the format
string has no variables inside it ;-)
I have adopted 02 05 03 (CLEAR) for analogy with the other printf() call,
so we have:
c4 = 47 ^ 02 = 45 'E' (MANDATORY)
c5 = 42 ^ 05 = 47 'G' (FOR EXAMPLE; see other
solutions at the end of this chapter)
02 0B 00 01
; get word pointed by global[0] and put in global[1]
00 02 46
; push global[1]
00 03 64
; pop at global[2] <- c5c4
00 02 47
; save global[0] on stack
; one word in the opcodes flow will be patched using a value derived
; from the password: put in local[0] the pointer to this word
00 01 530822D6
; push constant D8360D
00 03 66
; pop at global[0]
01 04 03 00098548
; global[3-3] += 98548 <- E1BB55
02 03 00
; dec global[0] <- E1BB54 pointer to word to patch
; modify that word xoring it with c5c4
01 03 02 01 00 ; *global[0] .wordXOR. global[2]
The remaining characters c6 and c7 will be determined analyzing the remaining opcodes:
00 03 66
; restore global[0] from stack
; global[2] <- c4+c6
E0B5E7 02 0A 00 02
; global[2] <- BYTE pointed by global[0]: c4
01 04 03 00000002
; global[0] += 2
02 0A 00 01
; global[1] <- BYTE pointed by global[0] c6
01 09 02 05
; global[5-3] += global[2-1] c4+c6
E1BB4E 05 00 00E1BB86
; call E1BB86
; three bytes instruction, modified in the previous snippet from 47 42 03 to 02 05 03
E1BB54 47 42 03->02 05 03 ; clear global[3] and NZflag
E1BB57 00 02 44
; push global[44^47=3] USELESS!
00 01 5311A8F3
; push encoded constant E1BC2A (congrats)
02 01 0236DE23
; call [E28052+2] MSVCRT!printf
00 04 4D
; adjust the stack += 8
04 00 F2F6DCD7
; jmp E1BB84 (exit)
; ko
E1BB6F 00 00 37195411
; push encoded constant 0 USELESS!
00 01 5311A8DC
; push encoded long E1BC13 "Please Authenticate!"
02 01 0236DE23
; call [E28054] MSVCRT!printf
00 04 4D
; adjust the stack += 4D^45(8)
E1BB84 02 00
; exit at retaddr
;
; sub E1BB86
;
; put 4E into global[1]
E1BB86 02 02 51021348 01
; global[1] <- 4C
02 04 01
; bump global[1] 4D
02 04 01
; bump global[1] 4E
01 04 04 00000005
; global[1] += 5 53
02 03 01
; dec global[1] 52
01 05 03 00000004
; global[1] -= 4 4E
; condition: c4+c6-5A == 4E, c4+c6 = A8 => 45+c6 = A8 => c6 = 63
01 05 04 0000005A
; global[2] c4 + c6 - 5A
01 0A 04 02
; global[4-2] CMP global[2-1] and put there
E1BBEF 04 01 00000131
; jnz E1BA3E+131 = E1BB6F ko
02 03 00
; dec global[0]: pointer to c5
02 0A 00 02
; global[2] <- BYTE pointed by global[0] c5
01 04 03 00000002
; global[3-3] += 2 pointer to c7
02 0A 00 01
; global[1] = c7
01 09 02 05
; global[5-3] += global[2-1] c5+c7
02 04 02
; bump global[2] c5+c7+1
01 05 04 0000004E
; global[2] -= c5+c7-4D
; global[0] <- pointer to return opcode to decrypt (E1BC11)
00 01 5310CA2D
; push encoded E0DD64
00 03 66
; pop at global[0]
01 04 03 AC DE 00 00
; global[0] += DEAC E1BC10
02 04 00
; bump global[0] E1BC11
; decrypt 2-bytes return opcode 47 01 to 05 01
; MUST BE 47^42 05
; this means c5+c7-4D == 42 => c7 = 8F-c5
01 03 02 00 00
; *global[0] byteXOR global[2] E1BC11
; as a further confirmation, the congrats string is decrypted
02 02 45 13 02 51 03
; global[3] <- 0x49 counter
00 01 5311A8F3
; push encoded
00 03 66
; pop at global[0] E1BC2A string to decrypt
02 04 02
; bump global[2]: XOR value 42+1=43
; decryption loop (XOR with constant byte)
E1BC00:
01 03 02 00 00
; *global[0] byteXOR global[2]
02 04 00
; bump global[0] ptr to string
02 03 03
; dec global[3] counter
04 01 000001C2
; jnz (E1BA3E+1C2)E1BC00
E1BC11 47 01 -> 05 01 ; return
E1BC13 "Please Authenticate!\00A\00D"
; string to decrypt
E1BC2A-E1BC73
14 26 2F 20 2C 2E 26 6D 6D 6D 49 4E 06 3B 33 2F
2C 2A 37 63 25 2C 31 63 2A 37 63 27 2C 26 30 2D
64 37 63 2E 22 37 37 26 31 63 72 6D 3B 63 00 2C
36 31 37 26 30 3A 63 2C 25 63 0D 2A 20 2C 2F 22
30 63 01 31 36 2F 26 39 43
We can finally discover the four possible solutions:
The mandatory values are 1D3nE_c_
As an alternate method, specially if we are not yet very confident with the
Opcodes meaning, and we do not know what to patch at addresses E1BB54 and
E1BC11 (see the red addresses in the listing above), we can start from the
bottom, brute-forcing the byte which will correctly decrypt the
congratulations string.
A simple program which will do the job has been included with the name
getcongrats.c
As a summary for the above analysis, I will try to answer the questions
required by the challenge.
Written with VIM on 1-2 december 2004, by bilbo.