============================
[MSLRH] v0.2 - manually unpacking tutorial
============================
MSLRH 0.2 is quite simple protector with one interesting function. It has option to
emulate Entry Point of SFX code with signature bytes from others protectors/packers
to fool PEiD. This tutorial will try to descrybe this protector.
1. Tools and requirements>
- OllyDbg 1.10
- LordPE
- ImpREC
- Target and packer itself is here in this archive [bin]
- Tutorial was written on windows XP, don't know will it work on other systems.
2. Studing protector
First, uncheck all exceptions in olly debug options except those in kernel32.
Open our target file keygebme1.exe in Olly and take look at next picture. Ups, before
that scan file with PEiD to see what PEiD will sad about packer. PEiD gives "SVKP 1.11 ->
Pavol Cerven". PEiD is wrong. Problem is that PEiD has small signature for SVKP so it can
be very easy emulated by another packer or even you can throw it in some of yours programs.
And this is just what this packer is doing. It can emulate couple well known packers /
protectors to confuse some unexperienced cracker. But it is not hard to find that MSLRH
is what we have under our hands. Lets see how it looks:
I think that comments on the picture are enough to understand. Tracing and examing is
hard with all this junk and I wrote simple script that will remove most of junk. Run that
script (but when you are asked to use second part of the script, select NO) and then we
will go to examne code. Now is code really easy to read and you can see that this packer
doesn't have much of it's code. First thing that we will meet is RTDSC check. After using
script, there will be lot of NOP's around here so I didn't paste whole code fom olly. Here
is interesting part:
00408081 RDTSC ; Get nuber of cycles.
00408083 PUSH EAX ; Store it to the stack.
00408084 RDTSC ; Get again number of cycles.
...
0040809D SUB EAX,DWORD PTR SS:[ESP] ; Substract last value with one that is stored in stack.
...
004080A9 ADD ESP,4 ; Pop first value from stack to free stack.
...
004080C3 CMP EAX,0FFF ; Now, compare is that difference bigger than FFF.
...
004080D2 JBE SHORT keygenme.004080EF ; If not, jump to normal program work, else go to
... exception that will crush program.
004080DE INT3
004080DF MOV AX,0FE
...
004080EC OUT 64,AX
004080EF NOP ; Here lands good jump.
...
...
RDTSC returns number of clock cyles to EAX (that is some number of instructions that has been
passed until that moment in whole system), then that value is pushed to stack and again is
called RDTSC which gives to EAX new value. Then those values are substracted. If you trace
trough program slowly, that difference will be much bigger and packer will assume that it has
been debugged. But if you just place bp on good spot and run it, that difference will be below
FFF and packer will not notice us. Not something that will slow us. Ok, there is nothing
interesting now for a while so scroll all way down up to this place:
First packer prepares for exception handling. Ok, you may ask, what the hell I'm talking about now.
This is not tutorial about exceptions so here is a quick and short info:
"The idea of exception handling (often called "Structured Exception Handling") is that your
application installs one or more callback routines called "exception handlers" at run-time and
then, if an exception occurs, the system will call the routine to let the application deal with
the exception. The hope would be that the exception handler may be able to repair the exception
and continue running either from the same area of code where the exception occurred, or from a
"safe place" in the code as if nothing had happened."
Our packer has installed exception handler here
004089BD PUSH DWORD PTR FS:[0]
004089C4 MOV DWORD PTR FS:[0],ESP
and then it will make one exception, INT 3.
If we don't understand how to manually deal with this or any kind of exceptions, we will make
something wrong and crush our program. But we can pass this in a such way that we left program
and windows to deal with exception as they do it without presence of debugger. We can do that by
simoly pressing Shift+F9. But there we have one problem - we don't know from which point after
exception program will continue it's normall work further. Well, I know from which point it will
continue, but that is very hard to find in obfuscated programs and also, that point can be anywhere
in the code. But this packer is after removing junk really easy to follow and we can find our
point after scrolling down:
This works something like PUSH-POP. Maybe I'm not quite right, but newer mind that. Below this you
will see one JB and lot of some junky code below. Take look at picture and you'll get clear all.
Code below JB is encrypted and this small loop wil just decrypt it. Do it and there you will find
procedure that will get address of GetProcAddress API, then check is it breakpoint placed on it, and
then it will enter in second decryptor loop which will decrypt another part of code below it:
00409DC0 CMP BYTE PTR DS:[EDI],0CC ; Checking for a bp on GetProcAddress.
00409DC3 JNZ SHORT keygenme.00409DCE
00409DC5 XOR ECX,ECX
00409DC7 XOR EDI,EDI
00409DC9 JMP keygenme.004089B1
00409DCE PUSH EDI
00409DCF PUSH EBX
00409DD0 XOR ECX,ECX
00409DD2 CALL keygenme.00409DD7
00409DD7 POP EDI
00409DD8 ADD EDI,1C
00409DDE MOVZX EAX,BYTE PTR DS:[ECX+EDI]
00409DE2 XOR EAX,65
00409DE5 MOV BYTE PTR DS:[ECX+EDI],AL ; Decrypting code.
00409DE8 INC ECX
00409DE9 CMP ECX,134
00409DEF JB SHORT keygenme.00409DDE
00409DF1 POP EBX
00409DF2 POP EDI
00409DF3 MOV SEG?,WORD PTR DS:[ESI+2A] ; Encrypted code which wait for decryption.
00409DF6 ADC BYTE PTR DS:[ECX],DL
After code below is decrypted, trace to there. This code is little obfuscated but you will
see that it's purpose is to get some API addresses using GetProcAddress and that it checks
for bp on every API and then it calls it. Example:
00409E12 CMP BYTE PTR DS:[EDI],0CC ; Bp check before CALL below.
00409E15 JNZ SHORT keygenme.00409E20
00409E17 XOR ECX,ECX
00409E19 XOR EDI,EDI
00409E1B JMP keygenme.004089B1
00409E20 CALL EDI ; kernel32.GetProcAddress
There are two API's that protector uses against debugging:
OutputDebugStringA - that is API that will exploit security bug in Olly and crush it. Armadillo
uses this API too. Just NOP that CALL it in our example:
00409E40 CALL EAX ; kernel32.OutputDebugStringA
IsDebuggerPresent - what to say, you know what this means. Use plugin now to hide olly, that's
the easiest way.
00409ED4 CALL EAX ; kernel32.IsDebuggerPresent
00409ED6 PUSH EAX
00409ED7 MOV EAX,DWORD PTR FS:[30]
00409EDD TEST EAX,EAX
00409EDF JS SHORT keygenme.00409EF0
After that, there is another loop that decrypts another pice of protectors code:
00409F35 MOVZX EAX,BYTE PTR DS:[ECX+EDI]
00409F39 XOR EAX,61
00409F3C MOV BYTE PTR DS:[ECX+EDI],AL
00409F3F INC ECX
00409F40 CMP ECX,1D28
00409F46 JB SHORT keygenme.00409F35
Let it decrypt and scroll waaaaaaaaaaay down to:
0040A8DE OUT 64,AX
0040A8E1 POP EAX
Does that look familiar? Yes, it is again those macro junk code, use script for cleaning
again (and again chose NO for second part). Good, everything is clear now. Again, we have
same RDTSC checks and one INT 3, just ignore all because this decrypted code there is nothing
new or interesting. Scroll down to the this place which was not encrypted from the very beggining
of protectors code:
0040C735 CALL keygenme.0040C73A
That pice of code which is little obfuscated hides procedure that decrypts original code
section of packed program. Now is time to use second part of my de-junk script. After usage
(I removed NOP's to reduce size of text) you will get picture like below. This part calculate
some CRC walue from protectors code and then it decrypts code section of packed program with
that value. It also holds some stolen bytes. Check my comments:
0040C742 POP ECX ; ECX=40C742 - address where this opcode is.
0040C74D SUB ECX,5 ; ECX=ECX-5 - it's upper limit addres for CRC calculation,
0040C75A XOR EBX,EBX it will not take bytes from this procedure for calculation.
0040C766 MOV EAX,4726 ; EAX=4726 is number of bytes of protector code.
0040C775 MOV EDI,ECX ; EDI=that upper address/end of code.
0040C781 SUB EDI,EAX ; Remove size of code because it will exclude emulated EP for PEiD trick.
0040C78D MOVZX EAX,BYTE PTR DS:[EDI] ; Start taking bytes from beggining.
0040C79A ADD EBX,EAX ; EBX will hold CRC summ.
0040C7A6 INC EDI ; Increase address.
0040C7B1 CMP EDI,ECX ; Check did we came to the end.
0040C7BD JB SHORT keygenme.0040C78D ; If not - continue calculating.
That was CRC calculation. Then it's gona start decrypting of code section of original program:
0040C7BF MOV EDI,keygenme.00401000 ; Base address of code section.
0040C7C4 MOV ECX,3000 ; Size of code section.
0040C7D3 MOVZX EAX,BYTE PTR DS:[EDI] ; Take byte from code section.
0040C7E0 ADD BL,BH ; Little caclulating here....
0040C7E2 XOR BL,BH
0040C7E4 XOR AL,BL
0040C7F0 MOV BYTE PTR DS:[EDI],AL ; And place decrypted byte instead encrypted one.
0040C7FC INC EDI
0040C807 DEC ECX
0040C812 JNZ SHORT keygenme.0040C7C9 ; Do all that again until section is decrypted.
0040C814 CALL keygenme.0040C819
0040C819 POP ECX
0040C81A SUB DWORD PTR DS:[ECX+15],EBX ; This will calculate OEP place.
0040C81D POPAD
0040C81E PUSH EBP ; Stolen bytes!
0040C81F MOV EBP,ESP
0040C821 PUSH -1
0040C823 PUSH keygenme.004040B8
0040C828 PUSH keygenme.00401F30
0040C82D PUSH 6262C0 ; This should be OEP value.
0040C832 RETN
I think that you understand everything, but few words more:
Protector has decrypted code section, but with bad CRC value because we have remove junk
code so code section is destroyed and not decrypted. Also, this last PUSH 6262C0 holds value
that subtracted with CRC value gives OEP address of packed program.
This SUB DWORD PTR DS:[ECX+15],EBX will subtract it and we should get OEP to which will last
RETN throw. But again, because we modified code, that value is incorrect and our program will
crush just for that. Also that is not quite correct OEP because we have couple stolen opcodes
from OEP, but that is not problem. How to fix that? Read next chapter.
3. Unpacking
This is really easy job now when we know what we have to do. Restart target in olly and use
IsDebuggerPresent plugin to hide olly. Then set in the command line hardware breakpoint on
execution on OutputDebugStringA API (hardware because normal-software protector can find). It
goes like this "he OutputDebugStringA" and hit ENTER button. In Olly debug options IGNORE ALL
exceptions this time, we don't need them anymore. Run target and you should break in kernel
to our debug string API:
77E9B493 >PUSH 22C
77E9B498 PUSH kernel32.77E9BE60
...
...
77E9B4D9 RETN 4
On your machine this API can look different (maybe). Remove hardware bp and instead first opcode
in API, place ast one, the RETN 4. It should look like this:
77E9B493 >RETN 4
77E9B496 NOP
77E9B497 NOP
77E9B498 PUSH kernel32.77E9BE60
...
...
77E9B4D9 RETN 4
Now press Alt+F9 to return to protector's code and scroll down. Down you will find that CRC loop
and OEP jump that is not encrypted:
0040C80F JMP SHORT keygenme.0040C812
Now just place bp on abowe opcode and run target. You will break here. Trace once with F7:
0040C812 JNZ SHORT keygenme.0040C7C9
0040C814 CALL keygenme.0040C819
0040C819 POP ECX
0040C81A SUB DWORD PTR DS:[ECX+15],EBX
0040C81D POPAD
0040C81E PUSH EBP
Place new bp on abowe place and run target again. Now code section is decrypted and you will jump
to "false" OEP. Write somewere stolen opcodes:
0040C81E PUSH EBP ; Stolen this and all below...
0040C81F MOV EBP,ESP
0040C821 PUSH -1
0040C823 PUSH keygenme.004040B8
0040C828 PUSH keygenme.00401F30
0040C82D PUSH keygenme.0040140A ; End of stolen bytes, this is value of false OEP
0040C832 RETN ; jump to false OEP
Execute last RETN, press Ctrl+A to analyse module and scroll little up:
004013FB POP EAX ; keygenme.00401F30
004013FC POP EAX ; keygenme.00401F30
004013FD POP EAX ; keygenme.00401F30
004013FE POP EAX ; keygenme.00401F30
004013FF POP EAX ; keygenme.00401F30
00401400 POP EAX ; keygenme.00401F30
00401401 POP EAX ; keygenme.00401F30
00401402 POP EAX ; keygenme.00401F30
00401403 POP EAX ; keygenme.00401F30
00401404 POP EAX ; keygenme.00401F30
00401405 POP EAX ; keygenme.00401F30
00401406 POP EAX ; keygenme.00401F30
00401407 POP EAX ; keygenme.00401F30
00401408 POP EAX ; keygenme.00401F30
00401409 POP EAX ; keygenme.00401F30
0040140A MOV EAX,DWORD PTR FS:[0]
00401410 PUSH EAX
00401411 MOV DWORD PTR FS:[0],ESP
00401418 SUB ESP,58
0040141B PUSH EBX
0040141C PUSH ESI
0040141D PUSH EDI
0040141E MOV DWORD PTR SS:[EBP-18],ESP
00401421 CALL DWORD PTR DS:[; kernel32.GetVersion
> Those POP EAX are junk and there you need to place stolen bytes. Then dump file with LordPE.
When you try to dump with LordPE, it will tell you that it can't grab process memory. Right
click in LordPE on our process, select "active dump engine", than "intelliDump" and "select".
Now dump it. You will get message that not all bytes could be dumped and that hey will be
substituted with zeros. Ok, save dump and open ImpREC. Reall OEP is 004013FB so write 13FB and
fix dump. And that's all!
4. Final words
It was not hard to unpack this version. I'm planing to write tutorial about MSLRH v0.32a which is
harder, but all in time. In the archive you will find script for de-junking and one for unpacking
this protector. Also you will find protector itself, packed target and unpacked target






جواب بصورت نقل قول
1CB ROR BX,1