September  1999
"Apispy v2.4"
( 'unpacking and patching'  )
Win '95 PROGRAM
Win Code Reversing
 
by The Snake
 
 
Code Reversing For Beginners
 
 
Program Details
Program Name: apis32.zip
Program Type: API utility
Program Location: Here
Program Size: 167kb
 
 
   

Tools Used:
 Softice V3.25 - Win'95 Debugger
W32Dasm V8.93 - Win'95 Dissembler
ProcDump v1.5 - Unpacker
 
Rating
Easy ( )  Medium (x)  Hard ( )  Pro ( )
 


Apispy v2.4
( 'unpacking and patching''  )
Written by The Snake
Introductionn

The author of  Apispy v2.4 says :

  APIS32 ( API Spy ) - is the best tool to examine Windows API functions used by 32 bit
  Windows  applications.
  It allows to examine any known API function`s calls that is resolved during the program
  load  time and is given by APIS32. APIS32 will work with Windows95/98/NT and Windows 2000
  applications which will be executed on the any Win32 platforms.
  Now APIS32 is working perfectly under Windows NT5 and Windows 2000 !
 
About this protection system

 This program was packed wih Petite v1.2, so this tutorial will be in 2 parts :
 part 1 - how to manually unpack a program packed with Petite v1.2.
 part 2 - how to crack apispy v2.4.
 When i followed the code of the protection routine, i saw how some of the program code changed in front
 of my eyes. You will see what i mean in the second part of this tutorial.
 The program save it's registration information in the registy file, not as string, but as binary value :
  HKLM\Software\APIS32\UserKey
  HKLM\Software\APIS32\UserName
 
The Essay

 PART ONE - how to manually unpack a program packed with Petite v1.2.

 When i start following the program with softice after i typed in my name and reg code, i found the place i need
 to patch the program in. So, i used W32dasm to create a dead list, and surprise, i couln't see any "exports"
 nor strings in the "string data references". This makes me think that this program is packed. Now we need to
 know what packer used for it. My chance was that some time ago i heard that it is "Petite 1.2".
 We're going to follow the steps to unpack it manually, because the option in ProcDump didn't unpacked it...
 When we need unpacking, we use "Softice Symbol loader" for it. So, load Softice symbol loader and in the
 menu choose "file/open" and put apis32.exe in it, now, choose "module/load". If you get a symbol/load
 error, click  on "yes", and Softice breaks on this code :

:0041A000 ffff                    invalid  ; press F10 once and here is the code :
 
:0041A002 60                      pushad
:0041A003 E8CA000000              call 0041A0D2              ; unpacking routine
:0041A008 0300                    add eax, dword ptr [eax]
:0041A00A 0400                    add al, 00

 Keep press F10 until u land on the call 0041A0D2, now press F8 to trace into this call, which is the unpacking
 routine.

 * Referenced by a CALL at Address:
|:0041A003
|
:0041A0D2 58                      pop eax           ; we land here
:0041A0D3 2C08                    sub al, 08
:0041A0D5 50                      push eax
:0041A0D6 8BC8                    mov ecx, eax
:0041A0D8 8BD0                    mov edx, eax
:0041A0DA 81C168D20000            add ecx, 0000D268
:0041A0E0 81C2DC150000            add edx, 000015DC
:0041A0E6 8920                    mov dword ptr [eax], esp
:0041A0E8 8BE1                    mov esp, ecx
:0041A0EA 50                      push eax
:0041A0EB 812C2400A00100          sub dword ptr [esp], 0001A000
:0041A0F2 FF30                    push dword ptr [eax]
:0041A0F4 50                      push eax
:0041A0F5 80042408                add byte ptr [esp], 08
:0041A0F9 50                      push eax
:0041A0FA 80042446                add byte ptr [esp], 46
:0041A0FE 50                      push eax
:0041A0FF 80042465                add byte ptr [esp], 65
:0041A103 50                      push eax
:0041A104 800424A1                add byte ptr [esp], A1
:0041A108 50                      push eax
:0041A109 800424BF                add byte ptr [esp], BF
:0041A10D 833A00                  cmp dword ptr [edx], 00000000
:0041A110 0F84A7140000            je 0041B5BD  ; from here it's a loop that executed 3 times
:0041A116 F70200000080            test dword ptr [edx], 80000000
:0041A11C 741B                    je 0041A139
:0041A11E FD                      std
:0041A11F 8B0A                    mov ecx, dword ptr [edx]
:0041A121 81E1FFFFFF7F            and ecx, 7FFFFFFF
:0041A127 8B742418                mov esi, dword ptr [esp+18]
:0041A12B 8BFE                    mov edi, esi
:0041A12D 037204                  add esi, dword ptr [edx+04]
:0041A130 037A08                  add edi, dword ptr [edx+08]
:0041A133 F3                      repz
:0041A134 A5                      movsd
:0041A135 83C20C                  add edx, 0000000C
:0041A138 FC                      cld
:0041A139 52                      push edx
:0041A13A FF32                    push dword ptr [edx]
:0041A13C 8B5A08                  mov ebx, dword ptr [edx+08]
:0041A13F 035C2420                add ebx, dword ptr [esp+20] ; OEP in ebx in first loop !!
:0041A143 53                      push ebx
:0041A144 8B5A04                  mov ebx, dword ptr [edx+04]
:0041A147 035C2424                add ebx, dword ptr [esp+24]
:0041A14B 53                      push ebx
:0041A14C E84A000000              call 0041A19B
:0041A151 85C0                    test eax, eax
:0041A153 741F                    je 0041A174
:0041A155 8B7C2404                mov edi, dword ptr [esp+04]
:0041A159 83C40C                  add esp, 0000000C
:0041A15C 5A                      pop edx
:0041A15D 8B4A0C                  mov ecx, dword ptr [edx+0C]
:0041A160 C1F902                  sar ecx, 02
:0041A163 33C0                    xor eax, eax
:0041A165 F3                      repz
:0041A166 AB                      stosd
:0041A167 8B4A0C                  mov ecx, dword ptr [edx+0C]
:0041A16A 83E103                  and ecx, 00000003
:0041A16D F3                      repz
:0041A16E AA                      stosb
:0041A16F 83C210                  add edx, 00000010
:0041A172 EB99                    jmp 0041A10D ; don't keep F10 on third time !!!!!!

 Trace the code with F10, but pay attention to the add ebx, dword ptr [esp+20] at location 0041A13F,
 when you pass it the first time, type "d ebx" in SI, the value in EBX is the Original Entry Point, that we
  will need  it later, so, note it done.
  What we need now is that the routine will finidh to unpack the program into the memory, so keep F10 untill
  you will come to jmp 0041A10D at location 0041A172 for the third time.
  When you do, we need ro freeze the program in memory, so we can use ProcDump to dump it and to have
  the full program. This is done doing this steps :
  type in Softice
  "a eip" and click "enter".
  "jmp eip" and click "enter"
  click enter
  The program is in endless loop now in memory, and we will exit Softice now by typing "x" and enter.
  We are going to use ProcDump now, you can go read the ProcDump setting page i wrote here.
  Run ProcDump and look in the upper window for apis32.exe. Right click on it will open window, choose the
  "full dump" option, and type the name you want to save it with. (i use apis23up.ex   up-unpacked).
  look now at the 2 files, do you see the different sizes ?
  Run the unpacked program... hey, it crashes, why ? the program is using the old Entry Point of the packed
  program. We need to change that.
  Open ProcDump again,  click on the "pe editor" button, and choose the unpacked executable apis32up.exe.
  You're looking now at the "header infos" window. take the note that you wrote the OEP and calculate the
  entry point this way : entry point = imagebase - OEP. In my case it was  00400000 - 00401000 = 00001000.
  Take the result of this calculation and write it in the Entry Point window, Push "ok" and leave ProcDump.
  That's it !!  go to w32dasm and create a "dead list", can you see the differences ??
  Program unpacked.

  PART TWO - how to crack apispy v2.4.
 
  Type in the registration window your name and a registration key and click "ok". The error message pops.
  Now, when we have a full list of the prog, go the the "string data references" and look for the error message.
  You will see it, and even the "good" message :
  "Thanks for Registering APIS32!"
  "The registration information you " double click on this message will take us to the location in the program
  that we get this message :

:00401764 FF15F8024100            Call dword ptr [004102F8]
:0040176A CC                      int 03                      ; we want to break here !
:0040176B 312F                    xor dword ptr [edi], ebp
:0040176D 0000                    add byte ptr [eax], al
:0040176F A374CE4000              mov dword ptr [0040CE74], eax
:00401774 EB01                    jmp 00401777
:00401776 B8                      BYTE B8

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401774(U)
|
:00401777 0AC0                    or al, al
:00401779 7402                    je 0040177D
:0040177B EB2C                    jmp 004017A9

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401779(C)
|

* Possible StringData Ref from Data Obj ->"The registration information you "
                                        ->"provided is incorrect. Please"
                                  |
:0040177D BFE8904000              mov edi, 004090E8
:00401782 BAE0D14000              mov edx, 0040D1E0

Type in the registration window your name and a registration key and before click "ok", fire up Si (Ctrl+d)
 and type in SI "bpx getdlgitemtexta" and "x" to leave. Click on the "OK", and softice break. Press F11
 once, and we're in apis32 code, but we want to set a new BP before the message appears, so, type "bd *"
 to disable the previous bpx, and type "u 40176a" (enter) when this location shows at the top of the code
 window, type "bpx 40176a" (enter) and "x" to leave. Now we are here :

 
:00401764 FF15F8024100            Call dword ptr [004102F8]
:0040176A E8312F0000              call 004046A0        ; we break here !
:0040176F A374CE400               mov [0040CE74],eax
:00401774 EB01                    jmp 00401777
:00401776 B80AC07402              mov eax,0274C00A
:0040177B EB2C                    jmp 004017A9

Well....  take a closer look at this code and at the one from the dead list. can you see the difference ?
But you didn't see nothing yet :) wait until we start trace it...  Here we go.
F10 once and we back from the call at 0040176a. register EAX is highlited and moved to location 40CE74.
BEFORE you F10 on :00401774 jmp 00401777, can you see this location ?? no, so what will be here is
that the EB01 (jmp 00401777) is jumping over the first pair of bits of the next op code :

B80AC7402 (mov eax,0274C00), to see what's the point, press now F10, here is what we got :

:0040176A E8312F0000              call 004046A0
:0040176F A374CE400               mov [0040CE74],eax
:00401774 EB01                    jmp 00401777      ; now press F10 over this line !
:00401776 B80AC07402              mov eax,0274C00A
:00401777 0AC0                    or al,al
:00401779 7402                    jz 0040177D       ; go to "error message"
:0040177B EB2C                    jmp 004017A9      ; go to "good message"

 This set of 2 new instractions, is our point of patch to register. As we saw, register EAX = 0 when we are
  back from the call, and this value is moved to location 40CE74, this location holds "0" or "1" to sighn if the
  prog is registered.. can we go and try to change the code so eax will get the value of "1" ?
  Enter your details again, and after SI breaks, when you over 00401777 or al,al we will change the
  content of eax this way : type "r eax=1" and "x" to leave.
  "thanks for registering" is here, but if we close the program again, it's still unregistered. There is other check
  also. If we look for the call 004046A0 we can see that it get called from 4 locations :

* Referenced by a CALL at Addresses:
|:004015CC   , :00401D1A   , :00401F39   , :004025E6
|
:004046A0 51                      push ecx
:004046A1 53                      push ebx
:004046A2 55                      push ebp
:004046A3 56                      push esi
:004046A4 57                      push edi
:004046A5 6A50                    push 00000050
:004046A7 68A0C64000              push 0040C6A0

* Possible StringData Ref from Data Obj ->"UserKey"
                                  |
:004046AC 6808964000              push 00409608
:004046B1 E81A030000              call 004049D0
:004046B6 83C40C                  add esp, 0000000C
:004046B9 83F810                  cmp eax, 00000010      ; UserKey need to be at least 10 hex
:004046BC 7D08                    jge 004046C6           ; 10h = 16 decimal
:004046BE 33C0                    xor eax, eax
 ----  snip snip ----
:004046C6 6A2F                    push 0000002F
:004046C8 6800CF4000              push 0040CF00

* Possible StringData Ref from Data Obj ->"UserName"
                                  |
:004046CD 68F8954000              push 004095F8
:004046D2 E8F9020000              call 004049D0
:004046D7 83C40C                  add esp, 0000000C
:004046DA 83F805                  cmp eax, 00000005      UserName need to be at least 5 hex
:004046DD 7D08                    jge 004046E7
----  snip snip ----
:0040481D 5F                      pop edi
:0040481E 85ED                    test ebp, ebp
:00404820 5E                      pop esi
:00404821 5D                      pop ebp
:00404822 0F94C0                  sete al
:00404825 5B                      pop ebx
:00404826 59                      pop ecx
:00404827 C3                      ret

 This locations executed when loading the prog, when click on the "about" button and when registering.
 Looking deeper, we can see some important notes about our reg info, but what interest us is location
 :00404822  sete al at this point we can move "1" to eax to make the program think that it's registered.
 The way i decide to do it this time is to use the code "inc eax" because all times i checked, eax was = 0
 at this point. The new code should look like this :

:00404820 5E                      pop esi
:00404821 5D                      pop ebp
:00404822 40                      inc eax
:00404823 90                      nop
:00404824 90                      nop
:00404825 5B                      pop ebx
:00404826 59                      pop ecx
:00404827 C3                      ret

 From now, evry time the program gets to this code eax will increase from "0" to "1" and act as registered.
 
The Patches

 Load up Spector.exe into your Hex-Editor ( I use hexWorkshop-32).

SEARCH FOR THE FOLLOWING BYTES : 5E5D0F94C05B59C3
REPLACE WITH HIGHLIGHTED BYTES : 5E5D4090905B59C3

REMEMBER, i'm doing my cracks as a hobby and challenge, so please, if you
like this utility and want to keep using it, support the author and pay for it.
 
Final Notes

 I must admit, that all this unpacking is very interesting to me, and i feel that there a lot to learn about it.
 The way the code inside the program executed, made all this experience even more interesting.

My thanks and gratitude goes to:-

The Sandman for all what he is doing for us, newbies.

Rhayader for helping me with Reverse Code Engineering and useful tips

Alpine, Lord Soth, Volatility and Torn@do for my basic knowledge in packed programs




Essay by:         The snake
Page Created: 2nd September 1999