|
Hello to everyone reading this new little paper. In this text file I'll try to describe my latest idea at patching a packed executable file. I'm sure that if you dealt with packed/encrypted programs, you know something about what can be done to patch them. The common methods are NO patching (trying to beat the protection from a different angle, like serial gen), unpacking then patching (not good if the person trying to 'crack' the program doesn't know how to unpack it), reversing the unpacking routine and patching the packed file itself (I think its pretty hard not to mention time consuming), and lastly, the best way, patching in program runtime. This last method can be done by either PPatcher or by writing a small exe that will patch in runtime using any condition we want (hooks and stuff).
|
|
You can find the ID crackme 5 on our site and if you look hard enough, you can also find my essay in text format, along with the CrackMe and a patch I made myself, so you'll see that this method actually works :)
|
|
The method I plan to show you here is a bit different, It does'nt involve
coding of
a patcher, unless you call comparing a patched file and the original
(and then generating
a patch), a patch :)
The steps involved:
1. Finding what we wanna patch,
and knowing the op-codes we want to replace, and their location.
2. Finding the place where
we jump to the Original Entry Point.
3. Finding a suitable place
in the original EXE to incorporate our 'patcher'.
4. Inject the code inside
to the location we found in step 2.
The method in general is based on the fact that the unpacking routine
is sitting inside the EXE just waiting for us to use it. Why don't use
it ?
Lets say that the program unpacks, and then we inject a snippet of
code, just before we go to the original entry point (OEP), that will patch
our now unpacked program. This way the program unpacks, and just before
jumping to the application, it goes through the new snippet which
in turn patches the program. Under most circumstances, this is possible,
since the process running has permission to write to his own code area
of course.
For demostration purposes (I had to see if it can be pulled naturally :), I will use a target program. I chose the Immortal Descendants CrackMe 5, which was coded by Torn@do. I chose this crackme because I only need to show the basic principal behind this method, and this is a relatively small program, and its packed with ASpack, which is a farily common packer.
What we'll try to do is this. After we run the crackme, we see a button
"About..". Clicking this button will pop up a dialog box with all
kinds of information :)
Our goal will be to patch this dialog so when we click on the About
button, nothing will happen, and we wanna do this with a simple patch.
Lets get to work then :)
Step 1 - Finding what we want to patch, location and op-codes
Ok, we wanna patch this dialog box, and there are several APIs for this. Instead of trying them all, lets find out what imports this program is using. Naturally, because this is a packed program, we can't look at the imports directly (with PE browse or a disassembly), so we'll need to go into the code and THEN find the imports. Here's a way to do it:
We need to find at least ONE API that this program uses. It does'nt matter which. In this case, I used a BP on WM_COMMAND when clicking on the About button, and then some tracing till I got to the crackme's code. Then I just looked inside for an API call. The tracing can be shortened, at least in Win9x by the following BP:
BPX k32thk1632prolog
Returning from this call (not an API), will bring us to something like this :
CALL [KERNEL32!K32THK1632PROLOG]
CALL [....]
CALL [KERNEL32!K32THK1632EPILOG]
This is a standard code inside windows, the middle CALL will take us
to another code area which if we trace through (not very long), will call
our program's Windows Procedure.
Of course, we need to get to this point by a BMSG as I described a
bit earlier.
Once we are inside the code, and we locate an API, we'll do
the following search (in my case I found a reference to ReadFile):
s ds:0 l ffffffff "ReadFile"
This will search the selector pointed to by DS from location 0 to the
end, and look for ReadFile. The caps
are imperative since the API names are case-sensitive in a search.
Once we land on the ReadFile string it should be around the data area
of our crackme, for me I found it at 0041XXXX and something :)
I landed in a data area containing the names of ALL imported APIs by
this program. I scrolled up and down a bit and looked for any reference
to a dialog box API, and indeed I found the following name: DialogBoxParamA
The next obvious thing would be to put a BPX on it:
bpx dialogboxparama
Continue execution, and click the About button, and then we'll be back in SI. F12 (P RET), will take us to the calling routine, and there we'll have the following snippet of code:
023F:004035D0 6A00
PUSH 00
023F:004035D2 68F0354000
PUSH 004035F0
023F:004035D7 A1B0EA4000
MOV EAX,[0040EAB0]
023F:004035DC 56
PUSH ESI
023F:004035DD 6A67
PUSH 67
023F:004035DF 50
PUSH EAX
023F:004035E0 FF1594124100 CALL
[USER32!DialogBoxParamA]
023F:004035E6 B801000000
MOV EAX,00000001
; <<<< WE ARE HERE!!
023F:004035EB 5E
POP ESI
023F:004035EC C21000
RET 0010
023F:004035EF CC
INT 3
We landed after the call to the dialog. Now, if we'll look at the Win32API
guide, we'll see that 5 parameters are being transferred to this API, and
those are the 5 PUSH instructions we see above the CALL. If we wanna get
rid of the dialog we'll need to skip those PUSHs and the CALL.
We'll assemble a little JMP instruction, type :
a 4035d0
Then we can enter the following code:
JMP 4035E6
As soon as we press Enter (assumind we have Code On), we'll see an EB14
instead of the 6A00 at memory location 004035D0. This is how our jump instruction
looks like in memory.
Remember these two bytes, we'll wanna write them to this location (004035D0)
when the program gets unpacked.
So far we've done nothing special. Its time to move to the next phase
of the plan :)
Step 2 - Finding the jump to the original entry point (OEP)
Ok, now we have to find when our program actually gets unpacked. This
is so that we'll know when we can safely patch the program.
Before we can even do anything, we need to be able to break with SI
on the beginning of the loader code. For that we'll use ProcDump.
Miz
wrote a great essay on how to manually unpack a program, and in there he
uses ProcDump's PE Editor to change the .TEXT section's attributes
from C0000040 to E0000020. This will tell the symbol loader that the .TEXT
section indeed contains CODE, and that it will break on it. For
those of you who have'nt read that essay, I suggest doing so now.
Finding the jump to the OEP may not be a trivial part. It ALWAYS requires some tracing into code, and might take a bit of time if you don't know the packer involved. A good guidline is to try to step over any calls and look at the SI window. Generally, when you'll see a few comments like:
Load32=..... and stuff like that, you'll know the program has been unpacked.
Now comes a tricky part. You have to monitor all the registers (normally
EAX) very closely and look for a potential OEP. In this case, the
OEP was stored in EAX, and it was 00405500 if I'm not mistaken.
Here is a little snippet of code of how ASpack does this jump:
023F:0042606A E822000000
CALL 00426091
023F:0042606F E88A020000
CALL 004262FE
023F:00426074 E80F030000
CALL 00426388
023F:00426079 E836030000
CALL 004263B4
023F:0042607E 8B853E6F4400
MOV EAX,[EBP+00446F3E]
023F:00426084 0385526F4400
ADD EAX,[EBP+00446F52]
023F:0042608A 8944241C
MOV [ESP+1C],EAX
023F:0042608E 61
POPAD
023F:0042608F 50
PUSH EAX
023F:00426090 C3
RET
023F:00426091 80BDA570440000 CMP
BYTE PTR [EBP+004470A5],00
023F:00426098 741D
JZ 004260B7
Notice those four CALLs there. After the fourth CALL we get the Load32
comment on the SI window, and then we know that we are green to patch.
Right after that, the OEP is calculated inside EAX, and it is pushed
on the stack, and using a RET, it actually jumps to the OEP, and
hence the start of the program.
Ok, our problems begin here actually. Now that we know where the unpacking
ends and the program begins, we need to inject a snippet of code that will
patch our dialog box.
Now, since we want to put our code between the unpacking routine and
that RET instruction, we'll have to be a bit creative. As you can see we
don't really have room to work here because every single byte is being
used somehow.
So this brings us to the next stage of the patch.
Step 3 - Finding a suitable place to inject our code to
So, what we know so far is how to patch and when we jump to the OEP.
We'll now search for a place to inject our malicious code :)
Open up your favourite hex editor and look for the hex string : 8944241C6150C3
This hex string is in fact the opcodes of the instructions at address
0042608A to 00426090.
After we find this pattern (there is only one in the EXE), we'll need
to find an empty place somewhere near it. I scrolled a bit down (a few
sections), and I found the following place:
023F:00426500 0C 89 46 10 83 C6 14 8B-95 52
6F 44 00 E9 B8 FE ..F......RoD....
023F:00426510 FF FF C3 AC AA 58 87 DB-00 20
00 00 08 00 00 00 .....X... ......
023F:00426520 00 00 00 00 00 00 00 00-00 00
00 00 00 00 00 55
...............U
023F:00426530 00 00 00 00 40 00 00 60-02 00
00 00 00 00 00 50
....@..`.......P
023F:00426540 02 00 00 00 00 00 00 00-00 00
46 60 00 00 00 10
..........F`....
023F:00426550 00 00 00 A4 00 00 00 C0-00 00
00 02 00 00 00 D0 ................
023F:00426560 00 00 00 1C 00 00 00 10-01 00
00 0A 00 00 40 28 ..............@(
023F:00426570 01 00 C0 1D 01 00 00 00-00 00
00 00 00 00 00 00 ................
023F:00426580 00 89 44 24 1C 61 66 C7-05 D0
35 40 00 EB 14 50 ..D$.af...5@...P
023F:00426590 C3 00 00 00 00 00 00 00-00 00
00 00 00 00 00 00 ................
023F:004265A0 00 00 00 00 00 00 00 00-00 00
00 00 00 00 00 00 ................
023F:004265B0 00 00 00 00 00 00 00 00-00 00
00 00 00 00 00 00 ................
023F:004265C0 00 00 00 00 00 00 00 00-00 00
00 00 00 00 00 00 ................
023F:004265D0 00 00 00 00 00 00 00 00-00 00
6B 65 72 6E 65 6C ..........kernel
023F:004265E0 33 32 2E 64 6C 6C 00 56-69 72
74 75 61 6C 41 6C 32.dll.VirtualAl
023F:004265F0 6C 6F 63 00 56 69 72 74-75 61
6C 46 72 65 65 00 loc.VirtualFree.
I saw this in the original file and I said : "what da ??? how can text
be right after program code ???". Then I realized that somewhere before
the text begins, the code ends. I decided to use those little zeroes we
see in there. BTW, this is a dump from SI, not from my hex editor, and
it is already patched, but lets leave that for now.
In short, I found a lot of zeroes I could turn into code. I loaded
the program in SI and when I got to the loader routine, I displayed the
code area in the data area:
d eip
I did this so I could look for the above text in the data window. Scrolling
a bit down I did find it in the location it was supposed to be. I figured
I found the place I could use to inject my code, but I had to make the
program execute to that point somehow.
Here comes the great part.
When I decided on a place to inject my code (I chose 00426581, it was easy to locate in the hex editor as well because of the pattern just a line before it), I went back to the end of the packer routine. In order for the CPU to execute instructions at 00426581 I had to put a jump there, so I assembled the following instructions:
a 42608A, and then:
JMP 00426581
Notice that this instruction is 5 bytes long. I could'nt just put it
instead of the RET instruction. So the solution was to copy the opcodes
of all the instructions this last JMP overwritten and put them in the new
location and then add my patching code.
Writing down the pattern: 894424106150C3
I will put my code between the 50 and the C3 (the C3 is the code for
the RET instruction, that will take me to the program, and I don't want
that before I patch!)
I assembled that pattern into 00426581:
MOV [ESP+1C],EAX
POPAD
and now I've added this line:
MOV WORD PTR [004035D0],14EB << This will put EB14 at the to-be patched location :)
and finished with:
PUSH EAX
RET
The whole thing now looks like this: 8944241C6166C705D0354000EB1450C3.
What have I done here in fact ??
What I did was to relocate a small part of the end of the unpacking
code so I could add my patcher's code to it. This has to be done in a place
that you KNOW that the program won't ever touch.
What was left to do was to patch the original EXE file using a hex
editor. We'll search for the end of the unpacker routine using this string:
894424106150C3
Once found, we'll change it to this: E9F20400009090 , which is the
JMP 00426581 along with two NOPs right after it, just to make it look nice
:)
The last step is to put the rest of the code where those zeroes were
before. I scrolled down in my hex editor and I found a familiar pattern
(look at offset 00426570). It was easy to see where 00426581 starts in
my hex editor once I had that point of reference. I put the code in, which
was (to remind you): 8944241C6166C705D0354000EB1450C3, and then I closed
everything up.
After the patch was done , we'll check that it actually works by running
to the program and clicking on the About button, which, if you followed
my instructions, should now be shooting blanks :)
All was left to do is to generate a patch using any patch generator
of your choice. That concludes this exercise, ladies and gentlemen :)
On this note, I used eGIS's MKpatch, in my opinion, the best patcher I've ever seen, simple, efficient, small and fast :)
|
lordsoth@immortaldescendants.com ICQ # 5178515 Greetings: Torn@do, Lucifer48, Jeff, BJanes, MisterZ-, +Sandman, Volatility, alpine, Miz, and all the other great crackers out there including +Fravia, +ORC, +Frog's Print and the others I don't remember. Of course if I left anyone out, I'm sorry, I'm just in a big hurry.
|