|   | 
	
	
		|   | 
	
	
		| Hacker Reversing Challenge 2007 Phase I 
		Problem & Solution | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		This is the international reverse 
			engineering challenge conducted by U.S based security company. The 
			purpose of this challenge is to evaluate the effectiveness of 
			software protections. The results of this effort is used to improve 
			the protection measures used in the softwares.  | 
	
	
		 
		The contest is carried out in 3 phases where first and third phase 
		involved breaking the protection of custom programs by using reverse 
		engineering. The interesting part of this reversing challenge is the 
		usage of floating point computations. 
		 
		For more details on various phases and the rules, visit the
		Hacker Challenge website. | 
	
	
		|   | 
	
	
		
		  | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		| The target binary program for the phase I, can be downloaded from 
		here. This contains the protected Windows binary program, readme file 
		with instructions, the solved program and the solution by Hacker 
		Challenge team. | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		Phase I of the challenge involved 
			breaking the protection of Windows binary program that produces 
			certain output. Goal of this challenge is to achieve following 
			objectives 
				- Reverse engineer the mathematical formula that results in 
				the value "10.9319" of the output. 
 
				- Remove the limitation on an input data field of the code so 
				that values greater than 210.5 are treated the same as values 
				less than 210.5. 
 
			 
		 | 
	
	
		 | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		The brief solution by Hacker 
			Challenge team is included along with target program. Here is the 
			complete report of various steps involved in breaking the protection 
			towards achieving the above mentioned objectives. This is the exact 
			report that was submitted as part of Hacker Challenge Phase 1 
			solution.  | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		| 
		Attacking the program started with analysis of the program using 
tools PEid (PE Packer Identifier) and PEditor (PE file viewer and editor). 
Here are the interesting things that have been found during this phase | 
	
	
		| 
		  | 
	
	
		
		
			- PEid 
indicates no packer. That means either it is not packed at all or not packed 
with any known packer.
 
			- Looking at the sections in PEditor, the last section named 
		'JR' looks 
suspicious. Also the OEP lies in this section. This is possible indication that 
code is packed.
 
			- Import section looks normal that means there will not be much problem with 
unpacking the file.
 
			- Also 
import section contains couple of interesting APIs such as IsDebuggerPresent, 
GetTickCount etc which says what sort of anti-debugging tricks have been used.
 
			- TLS 
table is empty.That means there is 
no TLS trick to worry about. Some protectors use TLS callback functions to 
perform anti-debugging actions.
 
		 
		 | 
	
	
		| 
		  | 
	
	
		| 
		Next the target program is loaded into IDA Pro disassembler for further 
		analysis. Looking at the sections in the disassembly mode, it is clear 
		that 'text' section is encrypted. IDA makes it easy to write comments as new 
things are discovered while attack is going on. Also it is easy to distinguish 
between library calls and internal functions calls using IDA.
		After the initial analysis is completed, I executed the program in 
the cmd prompt to see the output. First time it displayed the message saying 
		'Missing password.txt'.  Then I 
created the dummy text file with some values in it and named it as password.txt. 
This time it displayed the message saying 'Incorrect password'.   
		After collecting enough details about the program, it is time to get 
into action. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		The target program is loaded into OllyDbg with IDA pro showing 
disassembly of the same.  Program 
starts execution at address 
0x428288. 
After some series of jumps, it calls the function which begins at address
0x4284B9 and ends at 
0x4286EB. 
This function goes through each section header in the PE file and unpacks 
them.  Here is disassembly of main 
part of this function which checks for various sections by their name and then 
jumps to relevant code to unpack that section. | 
	
	
		| 
		  | 
	
	
	
	 
StartUnpacking:  
 
004284C8  
52                       
PUSH EDX 
004284C9  
50                       
PUSH EAX 
  
                                    
; checks if section name is '.text' 
004284CA  
3E:813E 2E746578         
CMP DWORD PTR DS:[ESI],7865742E 
 
004284D1  
0F84 C1000000      
       JE  UnpackTextSection 
  
                                   
 ; checks if section name is 'CODE' 
004284D7  
3E:813E 434F4445         
CMP DWORD PTR DS:[ESI],45444F43 
004284DE  
0F84 B4000000            
JE UnpackTextSection 
  
                                   
 ; checks if section name is 
'.data' 
004284E4  
3E:813E 2E646174         
CMP DWORD PTR DS:[ESI],7461642E 
004284EB  
0F84 E8000000            
JE  UnpackDataSection 
  
                                   
 ; checks if section name is 'DATA' 
004284F1  
3E:813E 44415441         
CMP DWORD PTR DS:[ESI],41544144 
004284F8  
0F84 DB000000     
        JE  UnpackDataSection 
  
                                   
 ; checks if section name is 'SSB' 
004284FE  
3E:813E 42535300         
CMP DWORD PTR DS:[ESI],535342 
00428505  
74 50                    
JE SHORT final.00428557 
  
                                   
 ; checks if section name is 
'.idata' 
00428507  
3E:813E 2E696461         
CMP DWORD PTR DS:[ESI],6164692E 
0042850E  
0F84 06010000            
JE final.0042861A 
  
  
                                   
 ; checks if section name is 
'.edata' 
00428514  
3E:813E 2E656461         
CMP DWORD PTR DS:[ESI],6164652E 
0042851B  
75 16            
         JNZ SHORT CheckRsrcSection 
  
0042851D  
52                       
PUSH EDX 
0042851E  
8BD5                     
MOV EDX,EBP 
00428520  
81C2 F0E74400            
ADD EDX,44E7F0 
00428526  
F702 80000000            
TEST DWORD PTR DS:[EDX],80 
0042852C  
5A                       
POP EDX 
0042852D  
0F84 28010000            
JE final.0042865B 
  
  
CheckRsrcSection:
                             
       ; 
checks if section name is '.rsrc' 
00428533  
3E:813E 2E727372         
CMP DWORD PTR DS:[ESI],7273722E 
0042853A  
75 16          
           JNZ SHORT final.00428552 
0042853C  
52                       
PUSH EDX 
0042853D  
8BD5                     
MOV EDX,EBP 
0042853F  
81C2 F0E74400            
ADD EDX,44E7F0 
00428545  
F702 80000000            
TEST DWORD PTR DS:[EDX],80 
0042854B
  5A                       
POP EDX 
0042854C  
0F84 42010000            
JE final.00428694 
00428552  
E9 83010000               JMP 
GotoNextSection 
  
   
GotoNextSection: 
                                                                        
;esi=esi+40,go to next section header 
004286DA  
83C6 28                  
ADD ESI,28 
004286DD  
58                       
POP EAX 
004286DE  
5A                       
POP EDX 
004286DF  
42                       
INC EDX 
  
                                    
;are we done with 5 sections ? 
004286E0  
66:3E:3B57 06            
CMP DX,WORD PTR DS:[EDI+6] 
004286E5  
0F85 DDFDFFFF            
JNZ StartUnpacking 
  
004286EB  
C3                       
RETN 
  
		 | 
	
		| 
		  | 
	
	
		| 
		At the beginning of each loop 
ESI 
points to name of the section, for example '.text'. Since this program does not 
contain 'SSB', 'idata' & 'edata' section, that part of the code does not get 
executed. 
		  
		Initially 
ESI points to '.text' (name 
of text section) and then jumps to address
0x428598.  Here it checks if the 
section->PointerToRawData and section->SizeOfRawData are not NULL. 
Then it pushes all the relevant parameters and calls the function which 
starts at 0x42847C 
		and ends at 
0x4284B8. 
This function decrypts entire text section by performing various 
operations on each byte.  After that it 
jumps to address 
0x4286DA
(look at the 'GotoNextSection' in the above code)
where it moves to next 
section header. 
		  
		Then it checks if we are done with unpacking all the 5 sections. 
		Otherwise it goes back to code at 'StartUnpacking'
(0x4284C8)
and performs the similar 
operations on other sections. For next iteration ESI points to '.rdata' section, 
but no action is taken and it just moves to the next section. 
		  
		 Now 
ESI 
is pointing to '.data' section and it jumps to code at address
0x4285D9 
which does basic checks and then calls the function at 
0x4286EC which decrypts 
		'data' section. After unpacking 'data' section it moves to '.rsrc' section. 
After comparison it jumps to code at address 0x428694 which does some basic checks and calls the function at 
0x428729 
which does some flag checks etc.  The 
last section to be checked is 'JR'. This time nothing happens and unpacking 
section comes to the end.
		  
		After the completion of unpacking process, it jumps to location
0x428890. There we have 
another jump which takes us to the location 
0x4289D0. 
Here we have following code | 
	
	
		| 
		  | 
	
	
		004289D0    BA B8 94 40 00    
  mov     edx, 
offset dword_4094B8 
		004289D5    FF E2               
jmp     edx
		
		  
		 | 
	
	
		| 
		This code puts the address 
0x4094B8 which lies in 'text' section into 
EDX and then jumps to it. This is nothing but the real OEP (Original 
Entry Point) of the target program. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Now the OllyDbg is standing still at real OEP
0x4094B8, 
it is time to dump the program using OllyDmp plugin. On launching OllyDmp it 
automatically fills in all the relevant values including the RVA of OEP as shown 
in the picture below. Note that 'Rebuild Import' checkbox is unchecked so as to 
dump the program without fixing the imports. 
On clicking the 'Dump' button, entire program from memory is dumped to 
file 'final_dmp.exe'. | 
	
	
		| 
		  | 
	
	
		| Figure 1: 
		Dumping the program using OllyDmp | 
	
	
		
		  | 
	
	
		| 
		  | 
	
	
		| 
		Next ImpREC ( Import Reconstructor ) is launched to fix the imports. 
Now in the ImpREC,  currently 
debugging process final.exe is selected, OEP field is changed 
0x94B8 
and then performed 'IAT Autosearch'.  
Then clicking on 'Get Imports' button, all the import functions from 
kernel32.dll is listed as shown in the picture below. Now the import table for 
the previously dumped file final_dmp.exe is fixed by clicking 'Fix Dump' button 
which creates new file final_dmp_.exe. 
To verify the entire operation, dumped program final_dmp_.exe is executed 
to see everything works as in original program. | 
	
	
		| 
		  | 
	
	
		| Figure 2: Fixing the 
		import table using ImpREC | 
	
	
		
		  
		 | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Now the fresh unpacked program final_dmp_.exe is launched into IDA 
pro for detailed analysis and also loaded into debugger, OllyDbg for live 
tracing. Quick analysis at IDA pro reveals that 'main ()' function begins at 
address
0x406F30. 
		   
		Now after tracing a bit, arrived at location 
0x406F82 
where it calls the function 
0x4065B0 which opens the 
		'password.txt' file.  If the file is 
not found, then it throws up the error 'Missing password.txt' and exits. 
Otherwise it proceeds to read the data from the file, by calling the function 
which starts at
0x406410. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		On reading data from the file, execution starts at address 
0x406FE8
where it converts the input string value to long using 'atol () ' function. After this it perform various 
computations on this value from
0x406FF1 
to 0x40700C as shown below. | 
	
	
		| 
		  | 
	
	
		                                    ; stores 
		the input value into ecx 
		00406FF1    
8B C8                 
mov     ecx, 
eax       
		
		
		  
		                                   
; performs series of operations on input  
		00406FF3    
B8 31 0C C3 30        
mov     eax, 
30C30C31h 
		00406FF8    
F7 E9                 
imul    ecx 
		00406FFA    
C1 FA 03              
sar     edx, 3 
		00406FFD    
8B C2                 
mov     eax, 
edx 
		00406FFF    
C1 E8 1F              
shr     eax, 
1Fh       
 
00407002    
03 C2                 
add     eax, 
edx 
		00407004    
6B C0 2A              
imul    eax, 2Ah 
		00407007    
8B D1                 
mov     edx, 
ecx 
		00407009    
83 C4 04              
add     esp, 4
		
		
		  
		                                   
; Is computed value matches input? 
		0040700C    
2B D0                 
sub     edx, 
eax 
		0040700E    
75 4E                 
jnz     short 
loc_40705E 
		
		
		  
                                   
; check for zero input value 
		00407010    
85 C9              
    test    ecx, ecx        
00407012    
74 4A                 
jz      
short loc_40705E
		
		
		  
                                   
; print 'Thank You' message 
		00407014    
68 44 E5 41 00        
push    offset 
strThankYou 
		00407019    
68 F8 54 42 00        
push    offset 
unk_4254F8 
		0040701E    
E8 4D EF FF FF        
call    
PrintString_405f70 | 
	
	
		| 
		  | 
	
	
		| 
		Once the operations are over, it checks if the final value matches 
with input value. In case of mismatch 'Incorrect password' message is shown and 
program is terminated. Otherwise it checks for zero input value and then 
proceeds to display the 'Thank You' message. 
		   
		There are 2 ways to defeat this password protection check. One way is 
to provide the right password and another way is to patch the jump instructions. 
From the analysis of the mathematical operations it is clear that input value 
should be multiple of 0x2A (42 decimal) . Hence any password value which is 
multiple of 42 will succeed. 
		  
		Another trivial way is to replace the 6 bytes from 
0x40700E 
to 0x407012 
		with 0x90 (nop) so that above check succeeds always. I used this 
approach and modified these bytes to defeat this password protection mechanism. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Once the password check is completed, execution starts at address
0x407023 
where it calls the function GetTickCount to get current time. The returned value 
is stored in EDI for using it later. This function is used to check if the 
program being traced in debugger. 
		   
		Next it checks if the program is being debugged. This is done by 
		checking if the 'BeingDebugged' flag in the PEB. 
If the program is debugged then this flag will be set to TRUE.This program uses following familiar instructions to perform this 
check. | 
	
	
		| 
		  | 
	
	
		| 
00407039    
64 A1 30 00 00 00           
mov     eax, 
large fs:30h 
		
		0040703F     
		0F B6 40 02           
		       movzx   
		eax, byte ptr [eax+2]  
		
		
		00407043     
		0A C0                       
		or     
		al, al 
		
		
		00407045     
		74 09                       
		jz     
		short loc_407050 
		 | 
	
	
		| 
		  | 
	
	
		| 
		This check is defeated by setting the value of 'BeingDebugged' to 
zero by using OllyAdvanced plugin.  
This is better method of defeating this check rather than patching the bytes 
since these checks are scattered throughout the program. 
		   
		Next the program jumps to location 
0x407077 where it calls the function IsDebuggerPresent to check for 
		the presence of debugger. Internally this function checks the value of 'BeingDebugged' flag of PEB. Since this flag 
is already set to zero, there is no need to worry.
		  
		After bypassing these checks, the program arrives at the location
0x407088. 
There is nothing interesting happens other than some initialization until the 
program reaches address 
0x40711B. Here it calls 
the GetTickCount function to get current time and then subtract the previous 
value from it.  Next it does the 
check to verify if the difference is less than 0x7D0. If not then that means the 
program is being traced. | 
	
	
		| 
		  | 
	
	
		| 
		 
		
		0040711B    FF D6               
		call    esi 
		; GetTickCount 
		
		
		0040711D    2B C7               
		sub     
		eax, edi 
		
		
		0040711F    3D D0 07 00 00      
		cmp     
		eax, 7D0h 
		
		
		00407124    76 07            
		    jbe    
		short loc_40712D 
		 | 
	
	
		| 
		  | 
	
	
		| 
		There are many ways to defeat this popular trick. One way is to use 
OllyAdvanced plugin which patches the GetTickCount function to make it return 
zero. But this will be risky if the program does checksum calculation of these 
API functions to make sure it is not altered. 
		  
		Here I have set the hardware breakpoint on GetTickCount function. 
When this function returns, tick count is stored in the 
EAX 
register.  So once the function 
returns, 
EAX 
value is changed to zero resulting in normal execution of the program. 
		  
		This anti-debugging trick is used 
at many places in the program and it is bypassed using the above mentioned 
method. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		After this execution continues normally and at location 
0x407146, 
it calls the function 
401230. 
This is interesting function which does the initialization of local structure 
that is later used during computation of output 
10.9319..! 
		  
		Next after tracing few instructions, program arrives at the location
0x40719B. 
		Here it invokes the function 
4065B0 which basically 
opens the 'data.txt' file for reading. 
Then the instructions from address 
0x4071B1 to 
0x40726E, read the
10 
input values from this file by calling the function at 
406410.
 After which all these string values are 
converted into long/float by instructions ranging from 
0x407282 
to 
0x4072EB by calling atol()/atof() functions. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Next the program execution 
continues at location 
0x4072F0. 
Here it checks if the input value is less than or equal to 210.5. The 
disassembly of the this verification process is shown below. | 
	
	
		| 
		  | 
	
	
		| 
		 
		                                                                       
		
		; Pushes 210.5 and then 8th input value 
		 
		
		
		                                   
		; onto floating point stack 
		
		
		004072F0    
		 DD 05 D8 E4 41 00     
		fld     
		ds:dbl_41E4D8 
		
		
		004072F6    
		 DD 45 D0              
		fld     
		[ebp+68h+varFloat8] 
		
		
		004072F9    
		 83 C4 28              
		add     
		esp, 28h 
		
		
		  
		
		
		                                   
		; Is 220 > 210.5??? 
		
		
		                                   
		; st(0)=220 & st(1)=210.5 
		
		
		004072FC    
		 D8 D1                 
		fcom    
		st(1) 
		
		
		  
		
		
		                                   
		; store the floating point status register 
		 
		
		
		004072FE    
		 DF E0                 
		fnstsw  ax 
		
		
		  
		
		
		                                   
		; The result is non zero if input value   
		 
		
		
		                                   
		; is less than or equal to 210.5 else it  
		
		
		                                   
		; will be zero 
		
		
		00407300    
		 F6 C4 41              
		test    ah, 
		41h 
		
		
		00407303    
		 75 08                 
		jnz     
		short loc_40730D 
		
		
		  
		
		
		                                   
		; input > 210.5, so use 210.5 only 
		
		
		00407305   
		 DD D8                 
		fstp    st 
		
		
		00407307    
		 EB 06                 
		jmp     
		short loc_40730F 
		
		
		  
		
		loc_407309: 
		 
		
		
		00407309    
		 32 DB                 
		xor     
		bl, bl 
		
		
		0040730B    
		 EB 71                 
		jmp     
		short loc_40737E 
		
		
		          
		 
		
		
		loc_40730D:                       
		; input <= 210.5, use the input 
		
		
		0040730D     DD D9                 
		fstp    
		st(1) 
		
		
		0040730F 
		
		
		  
		 | 
	
	
		| 
		If the input value is less than or equal to 
210.5 
then the value 
210.5 
is popped out from the floating point stack and supplied input value is used for 
computations.  Otherwise the input 
value (which is greater than 
210.5) is popped off the stack and value 
210.5 
is used for further operations. 
		  
		This limitation on the input value is defeated to make the program 
use the input value in all the cases by changing the opcode at instruction
0x407303 
from 75(JNZ) 
to EB(JMP). 
		This way it ensures that always input value (rather than 
210.5) 
is used in the output computations. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		After a bit of tracing from 
0x40730F, the program 
reaches the location 
0x40737E. 
Here it calls the function starting at 
401740 
that does the checksum calculation.  
This is to prevent any binary patching of the program. 
		 | 
	
	
		| 
		  | 
	
	
		| 
		 
		
		0040737E     E8 
		BD A3 FF FF        
		call    
		401740_CalculateChecksum 
		
		
		00407383    
		 3D 5C B5 1D D8        
		 cmp    
		eax, 0D81DB55Ch 
		
		
		00407388    
		 74 3A                 
		jz     
		short loc_4073C4 
		 | 
	
	
		| 
		  | 
	
	
		| 
		Since the binary is already patched to bypass the limitation on input 
value as mentioned in the preceding section, checksum here will not be correct. 
Hence to defeat this checksum verification, 
opcode at 
0x407388 
is changed from 
74(JZ)to EB(JMP), so 
that program always takes normal execution patch irrespective of checksum 
result. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Once the above patching is done, the program continues execution at
0x4073c4. 
Here it loads the target function address (0x401290) 
into the EDX 
and then calls it. This function at 
0x401290 
actually does the computation of output value 
10.9319.
 However at the beginning of this function 
there are few anti-debugging checks such as GetTickCount, IsDebuggerPresent etc. 
Once these checks are bypassed using the methods described earlier, it arrives 
at the location 
0x4012D8 
where the actual computation happens to produce output value 
10.9319. 
The disassembly of entire operations is given below. | 
	
	
		| 
		  | 
	
	
		| 
		   
		
		
		004012D8   8B 86 C0 00 00 00     
		mov     
		eax, [esi+0C0h] ; eax = 8  
		 
		
		
		004012DE   DB 05 68 30 42 00     
		fild    
		dword_423068    ; 
		st(0)=1efh(495) 
		
		
		004012E4   03 86 BC 00 00 00     
		add     
		eax, [esi+0BCh] ; eax +=11h(17) 
		
		
		004012EA   5F                    
		pop     
		edi              
		 
		
		
		004012EB   03 86 B8 00 00 00
		     add    
		eax, [esi+0B8h] ; eax+=0ah(10) 
		
		
		004012F1   8B C8                 
		mov     
		ecx, eax        ; ecx=eax=23h(35) 
		
		
		004012F3   0F AF C8              
		imul    ecx, 
		eax        ; ecx=4c9h(1225) 
		
		
		004012F6   89 44 24 08           
		mov     
		[esp+0Ch+var_4], eax 
		
		
		004012FA   DB 44 24 08           
		fild    
		[esp+0Ch+var_4] ; st(0)=23h(35) 
		
		
		004012FE   89 4C 24 08           
		mov     
		[esp+0Ch+var_4], ecx 
		
		
		  
		
		
		                             
		     ; 
		st(0)= st(0) * dbl_41E220 
		
		
		                             
		     ; 
		st(0)= 0.0289345 = 35 * 0.0008267 
		
		
		00401302   DC 0D 20 E2 41 00    
		   fmul    
		ds:dbl_41E220 
		
		
		  
		
		
		                             
		     ; 
		st(0)= dbl_41E218 – st(0) 
		
		
		                                  
		; st(0)=1.080445= 1.10938-0.0289345 
		
		
		00401308   DC 2D 18 E2 41 00      
		fsubr   
		ds:dbl_41E218 
		
		
		  
		
		
		                             
		     ; 
		push 4c9h(1225) onto float stack 
		
		
		                             
		     ; 
		st(0) = 1225 
		
		
		0040130E   DB 44 24 08            
		fild    
		[esp+0Ch+var_4] 
		
		
		  
		
		
		                             
		     ; 
		st(0)=st(0) * dbl_41E210 
		
		
		                             
		     ; 
		st(0)=0.00196= 1225 * 1.6e-6 
		
		
		00401312   DC 0D 10 E2 41 00      
		fmul    
		ds:dbl_41E210 
		
		
		                             
		   
		 
		
		
		                                  
		; st(1)=st(1)+st(0)=1.080445+0.00196 
		
		
		                             
		     ; 
		After addition, perform POP on fl.stack 
		
		
		                                  
		; Result: st(0)=1.082405, st(1)=495 
		
		
		00401318   DE C1                  
		faddp   st(1), st 
		
		
		  
		
		
		                             
		     ; 
		PUSH the value at address esi+30h 
		
		
		      
		                             ; then perform st(0) = st(0) * 
		dbl_41E208 
		
		
		                             
		     ; 
		result: st(0)=0.00849= 33 * 0.0002574 
		
		
		0040131A   DB 46 30               
		fild    
		dword ptr [esi+30h] 
		
		
		0040131D   DC 0D 08 E2 41 00      
		fmul    
		ds:dbl_41E208 
		
		
		  
		
		
		                             
		     ; 
		st(1)=st(1)–st(0)= 1.082405 - 0.00849 
		
		
		                             
		     ; 
		After subtraction, POP from fl.stack 
		
		
		                             
		     ; 
		Result: st(0)=1.0739, st(1)=495 
		
		
		00401323   DE E9                  
		fsubp   st(1), st 
		
		
		  
		
		
		                             
		     ; 
		st(1)=st(1)/st(0)=495/1.0739 
		
		
		                             
		     ; 
		After division, POP from fl.stack 
		
		
		                             
		     ; 
		Result: st(0)=460.9319 
		
		
		00401325   DE F9                  
		fdivp   st(1), st 
		
		
		  
		
		
		                             
		     ; 
		st(0) = st(0)+dbl_4248C0 =460.9319 + 0.0 
		
		
		00401327   DC 05 C0 48 42 00      
		fadd    
		dbl_4248C0 
		
		
		  
		
		
		                             
		     ; 
		st(0) = st(0)- dbl_41E1B8=460.9319-450 
		
		
		                             
		     ; 
		Result: st(0) = 10.9319 
		J 
		
		
		0040132D   DC 25 B8 E1 41 00      
		fsub    
		ds:dbl_41E1B8 
		
		
		  
		
		
		                             
		     ; 
		Finally store the result 10.9319 onto  
		
		
		                                  
		; local variable 
		
		
		00401333   DD 96 98 00 00 00      
		fst     
		qword ptr [esi+98h] 
		 | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		After couple of floating point 
operations, we arrive at location 
0x40132D which produces 
final result, 10.9319. 
		This value is stored into local 
variable for printing later. Then the function returns to main() after 
calculating few other output values. 
		   
		The entire series of floating point 
operations for producing the output 
10.9319 
can be put in the following equation form. Here global variables start 
with 'g' and local variables start with 'local' prefix. 
		 | 
	
	
		| 
		  | 
	
	
		
		
		
		   
		A 
= ( (local_ESI_C0h + local_ESI_BCh) + local_ESI_B8h)  
		 
		X 
= {g_41E218 - (g_41E220 * 
A) 
} + { (A* 
A) 
* g_41E210} 
		 
		Result= [{g_423068/(X -(local_ESI_30h * g_41E208))}+g_4248C0] - g_41E1B8
		  
		 | 
	
	
		| 
		Though the value of g_4248C0 is zero it is included as it was used in 
		computing the formula. The original solution from Hacker Challenge Team 
		does not have this in the equation. As a result my entire 15 page report 
		was termed 'PARTIAL Solution'. Looks like evaluators have forgotten 
		basic maths :) | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		Next in the main program execution continues from address 
0x4073D4. 
Here we encounter series of printing operations which calls the function
0x405F70 
for printing individual values. This goes on till the address 
0x407615
where we encounter 
another checksum calculation. The disassembly of the checksum verification 
process is given below. | 
	
	
		| 
		  | 
	
	
		| 
		 
		
		00407615      E8 E6 A0 FF FF        
		call    
		401700_CalculateChecksum2 
		
		
		  
		
		
		                                   
		 ; verify if the checksum 
		is correct? 
		
		
		0040761A      3D F7 B3 7A 50     
		    cmp    
		eax, 507AB3F7h 
		
		
		0040761F      74 0C                 
		jz     
		short loc_40762D  
		
		
		  
		
		
		                                   
		 ; if checksum failed, then 
		load new  
		
		
		                                    
		; value into dbl_4248C0 from dbl_41E4C8 
		
		
		00407621      DD 05 C8 E4 41 00     
		fld     ds:dbl_41E4C8 
		
		
		00407627      DD 1D C0 48 42 00     
		fstp    
		dbl_4248C0 
		
		
		0040762D 
		
		
		  
		
		
		loc_40762D:                            
		 
		
		
		0040762D       84 DB                
		test    bl, 
		bl         
		 
		 | 
	
	
		| 
		  | 
	
	
		| 
		This is the clever checksum verification than the one we encountered 
earlier. If the checksum is not correct then it just changes the value of one of 
the global variable 
dbl_4248C0
which is used in 
computation of final output values.  
Hence if there is any patching in the program, then the output will be 
different. 
		   
		To defeat this checksum verification, one has to just change the 
opcode at 
0040761F from 74(jz) to EB(jmp)so 
that it will follow normal execution path irrespective of the checksum result.
		  
		Then the program continues 
execution at 
0x407641 
where it prints remaining three rows by calling the function 
0x406CE0. 
Finally the program comes to an end at 
0x40767F. | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		
		
			- 
			Target program final.exe is unpacked to produce the original 
			binary file.
 
			- 
			Unpacked program is loaded into debugger and the anti-debugging 
			tricks are defeated by using OllyAdvanced plug-in and making use of 
			hardware breakpoints on system APIs.
 
			- 
			Password protection is defeated by replacing 6 continuous 
			bytes starting from address
			
			0x40700E with nop (0x90)opcode.
 
			- 
			Next the limitation on input value (210.5) is bypassed by 
			modifying the opcode at location 
			
			0x407303 
			from 
			0x75(jnz) to
			
			0xEB(jmp).
 
			- 
			After that function which computes output value 10.9319 is found 
			and reversed to produce the formula behind this operation.
 
			- 
			Finally all the checksum verification methods are disabled by 
			patching at the relevant locations so that program executes 
			normally.
 
		 
		 | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
		  |  	
	
		| 
		This is great challenge from reversing point of view especially due to 
		usage of floating point computations. Packing the program with custom 
		packer makes it difficult for casual cracker and prevents static 
		analysis of the program using disassembler. Also the checksum 
		verification technique is effective considering that program requires 
		patching to defeat the various protections. Though the anti debugging 
		techniques used in the program are basic ones, they are good enough to 
		deceive new players entering this reversing game. 
		
		 | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
	
		
	
	
	
		| 
		  | 
	
	
	 
		
			 
			Target Program & Solution for Hacker Challenge Phase I
		
		 |  	
	
	
	
		| 
		  
		   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		|    Hacker Reversing Challenge 2007  | 
	
	
		|    Hacker Reversing Challenge 2007 Phase III Problem and 
		Solution | 
	
	
		|    
		Tutorial on floating point calculations in assembly  | 
	
	
		|    Unpack UPX using OllyDbg  | 
	
	
		|    Faster method to enumerate heaps on 
		Windows  | 
	
		
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   |