Enigma protector 1.02 is another PE file protector. It is still in development and this version is a free demo without limitations. As a target for this tutorial I choose the protector itself because it has all options enabled that it has to offer us. Plus, unpacking a file that I didn't previously packed is chalenging because I do not know what the original was looking like. I must say that this protector gave me some problems, I was writing this tutorial (and that means unpacking it) for a couple of days. Tutorial is not hard to understand but since it's not linear (I was restarting target multiple times) , it is not for beginners. Let's say that it is on intermediate level. At the end of the tutorial, I will show how the protected target can be easily inline patched. Well, not so easy , but it can be easier than unpacking it.
The protector has few bugs. Main bug is in "Exit on file name option" because every file packed with that option is non-working. Reason is that protector leave to file name exclamanation character " (example test.exe becomes test.exe") so it thinks that every name is invalid. Virus check also can be buggy.
2. OEP and loading DLL
Reaching OEP can be very easy. Just use Olly tracing option and after some time OEP is found. Protector has IsDebuggerPresent check so we must use plugin to hide olly. This way of finding OEP will work if protected file doesn't emulate OEP of other compilers. Altough with little PE header altering Olly can find OEP in those cases too, later we'll see more generic approach for OEP. When we land on OEP, we will see that we are actually on "false" OEP and that some original OEP opcodes are "stolen":
"False" OEP is at 004F9918, above code is stolen. Olly tok lot of time to find OEP. In log window we can see some interesting informations:
****************************************************************************
Log data
Address Message
0066C8A4 Access violation when writing to [00000000]
0066C8A4 Access violation when writing to [00000000]
0066C8A4 Access violation when writing to [00000000]
0066C8A4 Access violation when writing to [00000000]
...
loooooot of memory access violation exceptions
...
0066CBEE Access violation when writing to [00000000]
0066CBEE Access violation when writing to [00000000]
0066CD84 Access violation when writing to [00000000]
0066CEBE Access violation when writing to [00000000]
00C24333 INT3 command at 00C24333
00C243E5 Access violation when writing to [00000000]
00C243EC Integer division by zero
...
...
...
00C26C10 Illegal instruction
004F9918 Possible entry point of SFX code
CRC changed, discarding .udd data
Analysing Enigma
3459 heuristical procedures
51 calls to known, 1275 calls to guessed functions
1038 loops, 313 switches
*****************************************************************************
We can see that protector consist from two parts, first is code attached at the end of main exe, and second is dll loader that is extracted in some allocated memory block. We can see that in attached part occurres lot of memory violation exceptions, most of them at same place. Those exceptions slow down program execution in debugger, particulary if you try trace trough it. But in that attached code, exceptios are all memory violations. When dll loader is extracted, first exception ocurred in it is INT3. So we could easily break in loader just by setting exceptions handling in Olly options.
But there is smarter way: Last exception in attached code is at 0066CEBE. I will place bp there , ignore all exceptions, will not use Olly tracing option this time, and restart target. Soon I break on my bp:
0012FF58 0012FFE0 Pointer to next SEH record
0012FF5C 0066CE84 SE handler <-------------------- Exception handler!
0012FF60 77EB6930 kernel32.77EB6930
0012FF64 00C00000 ASCII "MZP"
In stack you can see that local exception handler is at 0066CE84. That mean, after exception is coused, program will continue from that line. I'm going there:
Last RETN will throw us to ntdll.dll that handles exceptions but here is conclusion: Since we passed last exception before jumping to loader code, here around must be some jump or RETN that throw us to loader code. Little down I found last instructions that are executed before jumping:
0066CF6E EB 01 JMP SHORT Enigma.0066CF71 <---- It jumps to obfuscated RETN below!
0066CF70 9A C35589E5 FF75 CALL FAR 75FF:E58955C3
0066CF77 0C FF OR AL,0FF
0066CF79 75 08 JNZ SHORT Enigma.0066CF83
0066CF7B E8 46000000 CALL Enigma.0066CFC6
0066CF80 8B7D 08 MOV EDI,DWORD PTR SS:[EBP+8]
...
...
We are at the entry point of loader dll. This dll will unpack/unprotect original file in memory, it will do all tricks to prevent debugging and dumping. We can even dump this file to disk and repair it, I will do this later just for fun. Scrolling up to beggining of section you will get address of it's base. Because this dll will probably be loaded on different base on your machine, it is good thing to know it's base because then you can find all addresses relative to it. What we know untill now:
Jump_to_loader_code = 0066CF71
Loader_Image_Base = 00C00000 (on my machine)
Loader_OEP = 00C2720C (on my machine)
Loader_relative_OEP = +2720C
3. Integrity traps
One wery annoying thing is that this protector has many internal integrity checks that detects every normal or memory breakpoint. Also protector kills/corrupts hardware breakpoints and examning loader code is hard because I had to use lot of breakpoints, then delete them to not be found. Protector uses lot of crypto algorithms for checking. After dumping this dll to disc I scaned it with PEiD's Kanal crypto plugin which found next signatures:
BASE64 encoding (used e.g. in e-mails - MIME)
CRC32 precomputed table for byte transform
MD5 transform ("compress") constants
TWOFISH: pregenerated 8x8 Sbox table
Well, this is not some information that will help me in unpacking , but it's interesting to know.
To find where check of dll is performed, I just placed memory bp on access on dll OEP and I stopped here:
That is procedure that produces some hashes. It is used couple times. It's RVA from base of dll is +1FEE8 and that is same in every target. That line, PUSH EBP is called from two places. You can easily find them "finding references to selected command", those two calls are just up at +1FE86 and +1FEAB. But I'm going too much in that direction. Those who like and know crypto can research that.
So, conclusion is that next important address is +1FEE8 or 00C1FEE8 in my case. Protector also has integrity checks for unpacked sections of file. If we make some changes after sections are unpacked, we will get error Message Box saying that virus damaged file. I used memory bp on location where I sow that message is create and found that check is here:
Jump above must be executed if we want to pass that check. It's relative address from base is +1DA11 and that is one more important address to remember. Actually not so much important. That check isn't important for unpacking, it is not even important in inline patching because changes can be made after this check.
4. OEP and stolen bytes
Let we return to OEP problem. For finding OEP we will use previous metnioned procedure that checks integrity in loader. Reason is that after last one check, that code is going straight to OEP (well, not straight but close). First we get to loader OEP (we already sow how to do it). Then place memory bp somewhere to stop in check procedure. We will break there
Idea is to count how many times will this procedure be executed before program starts. Then we do it again and stop at RETN 8 of last execution. But you must be careful. When you break at C1FF08 when memory is being read, remove that mem bp and place hw bp at RETN 8. Then place toggle bp on start of procedure 0C1FEE8. By switching breakpoint and hw bp, you will avoid detection and crushing (note: delete hw bp too). After 4 times program started. Do it all again and 4. time just trace with F7:
00D39E70 E8 08000000 CALL 00D39E7D
00D39E75 EF OUT DX,EAX ; I/O command
00D39E76 28E2 SUB DL,AH
...
cut
...
00D3B943 51 PUSH ECX
00D3B944 5E POP ESI
00D3B945 5E POP ESI
00D3B946 FEC9 DEC CL
00D3B948 68 18994F00 PUSH 4F9918 <----------------- Address of false OEP!
00D3B94D 60 PUSHAD
00D3B94E 31C0 XOR EAX,EAX <----------------- You can (and should) NOP from here...
00D3B950 B9 D81A0000 MOV ECX,1AD8
00D3B955 BF 709ED300 MOV EDI,0D39E70
00D3B95A F2:AA REPNE STOS BYTE PTR ES:[EDI]
00D3B95C 47 INC EDI
00D3B95D AB STOS DWORD PTR ES:[EDI]
00D3B95E AB STOS DWORD PTR ES:[EDI] <----- ...to here. It will prevent crushing.
00D3B95F 61 POPAD
00D3B960 C3 RETN
00D3B961 0000 ADD BYTE PTR DS:[EAX],AL
00D3B963 0000 ADD BYTE PTR DS:[EAX],AL
00D3B965 0000 ADD BYTE PTR DS:[EAX],AL
This huge junky code holds stolen OEP code. I didn't bother to try find exact bytes because program will work with this block attached to main dump. Code that must be NOP-ed is used to delete all those code with stolen bytes. It must be patched because in main dump, it will try to erase bytes in 00D3xxxx block (it won't be there in dumped file) and that will couse exception. Place bp on RETN, run, execute RETN and there is our (false) OEP:
Now we know how OEP can always be found, also we know that stolen code can be fixed by just adding section. I binary copied stolen bytes and saved it in StolenCode.txt file. I can use it later.
5. Code relocation
Enigma has some "Extra relocations protect" option which redirects whole one section. Check this:
004F9918 E8 5BCAF0FF CALL Enigma.00406378
004F991D 8B1D E4303E00 MOV EBX,DWORD PTR DS:[3E30E4] <--- This is what I'm talking about.
004F9923 8B03 MOV EAX,DWORD PTR DS:[EBX]
...
...
It redirected whole section to some virtual address and changed all opcodes that points to original section. There is easy way to prevent this. Enigma uses VirtualAlloc to allocate that block. When block is allocated, all we need to do is change EAX=003E0000 to original section value and enigma will direct all to that section. How to break on right place? Using memory breakpoints. This line
needs to be changed. More correct, these four bytes E4303E00. Restart target in olly, go to 004F991D+2=004F991F in dump and place mem bp there on 1 byte. Run Olly and you will break couple times in loader code. Wanted one is here:
Scroll up and we can see where it calls VirtualAlloc:
00C26AAF E8 E0F2FDFF CALL 00C05D94 ; JMP to kernel32.VirtualAlloc
That address is +26AAF from dll base. Address that is worth to remember. You need to break there somehow which again includes avoiding geting cought. Find your way. When you break on right line,
you need to change EAX value in second line. EAX must have base of original section. To find that, go now to 004F991D where code needs to be changed. You will see that it points somewere in 004FA000 section and that is original one. It means you must set EAX=004FA000. Then place memory bp on false OEP (erase all others) and run untill you break there:
Check section there and you'll see that is OK. Let again see what we know till now:
Jump_to_loader_code = 0066CF71
Loader_Image_Base = 00C00000 (on my machine)
Loader_OEP = 00C2720C (on my machine)
Loader_relative_OEP = +2720C
Internal_check = +1FEE8 (00C1FEE8 on my machine)
Section_check = +1DA11 (00C1DA11 on my machine)
Jump_to_stolen_code = +20565 (00C20565 on my machine)
Code_relocation = +26AB4 (00C26AB4 on my machine)
6. General IAT problem
Enigma has three ways of import handling. First is completly removing whole IAT from IAT section, thunks are placed in some allocated memory block. Second, imports are little emulated/obfuscated. Then, it can combine both of that features together, remove and obfuscate. Third option, it can emulate some whole API's. This also can be combined with first feature. Our target has all this tricks included. Let's see one example: This is first import jump in exe:
It points to some dword at 00D36F14 address but original jump should point to some dword in 00603000 section which was original IAT section. And dword that is placed there should be some API address, for example 77665544 but our dword is [00D36F14]=00C43268. We can follow that address:
These opcodes are emulated first couple instructions of GetStdHandle API, then PUSH-RETN combination jumps someware in the middle of API. This was eaxample of removing IAT and emulating couple first opcodes. I found way how this can be little changed to help ImpREC fix imports. I found that these two jumps are important:
00C1ECE3 0F87 300A0000 JA 00C1F719 <------------------------- This one!
00C1ECE9 FF249D F0ECC100 JMP DWORD PTR DS:[EBX*4+C1ECF0]
00C1ECF0 F0: PREFIX LOCK:
00C1ECF1 F0:C100 FC LOCK ROL DWORD PTR DS:[EAX],0FC
00C1ECF5 F0:C100 08 LOCK ROL DWORD PTR DS:[EAX],8
00C1ECF9 F1 INT1
00C1ECFA C100 14 ROL DWORD PTR DS:[EAX],14
00C1ECFD F1 INT1
...
00C1F719 803C24 00 CMP BYTE PTR SS:[ESP],0
00C1F71D 0F84 A6000000 JE 00C1F7C9 <------------------- And this one (comes after first one)!
00C1F723 33C0 XOR EAX,EAX
00C1F725 8AC2 MOV AL,DL
00C1F727 83F8 78 CMP EAX,78
00C1F72A 7F 35 JG SHORT 00C1F761
00C1F72C 74 79 JE SHORT 00C1F7A7
00C1F72E 83C0 90 ADD EAX,-70
00C1F731 83F8 07 CMP EAX,7
00C1F734 0F87 8F000000 JA 00C1F7C9
00C1F73A FF2485 41F7C100 JMP DWORD PTR DS:[EAX*4+C1F741]
...
Distance first one from loader base is +1ECE3 and second one +1F719. Why are those jumps important? Because code below them is emulating api's. If those jumps are patched to JMP, all import jumps of that type will now look like this:
And this is combination which ImpREC can easily find and repair. But jumps are still pointing to allocated block JMP DWORD PTR DS:[00D36F14]. There is way to fix that too. Restarting , placing memory breakpoints on address where import jump should be, stoppin couple times and finally I break on place where jumps are redirected:
00C1E457 037D 00 ADD EDI,DWORD PTR SS:[EBP]
00C1E45A 890F MOV DWORD PTR DS:[EDI],ECX <------ Here it changes jump pointers!
00C1E45C 40 INC EAX
00C1E45D 4A DEC EDX
00C1E45E ^75 D0 JNZ SHORT 00C1E430
00C1E460 43 INC EBX
00C1E461 FF0C24 DEC DWORD PTR SS:[ESP]
00C1E464 ^75 B2 JNZ SHORT 00C1E418
00C1E466 5A POP EDX
00C1E467 5D POP EBP
00C1E468 5F POP EDI
00C1E469 5E POP ESI
00C1E46A 5B POP EBX
00C1E46B C3 RETN
That line will change
004012AC FF25 18326000 JMP DWORD PTR DS:[603218]
to
004012AC -FF25 0B6FD300 JMP DWORD PTR DS:[D36F0B]
Let's remember this address too 00C1E457 or +1E45C. I have fixed that problem with injecting little code. Instead these two lines, I placed jump to empty space where I will add couple more lines:
There I will inject some code. This code will not change jumps (I excluded MOV DWORD PTR DS:[EDI],ECX line which is doing that), it will place pointers in original IAT section.
I will fix fully emulated API's later, that is harder problem.
7. Dumping and repairing
And finally, I have now enough informations for making dump that is worth to dump. Let's repeat important addresses because I must all over again restart target:
Jump_to_loader_code = 0066CF71
Loader_Image_Base = 00C00000 (on my machine)
Loader_OEP = 00C2720C (on my machine)
Loader_relative_OEP = +2720C
Internal_check = +1FEE8 (00C1FEE8 on my machine)
Section_check = +1DA11 (00C1DA11 on my machine)
Jump_to_stolen_code = +20565 (00C20565 on my machine)
Code_relocation = +26AB4 (00C26AB4 on my machine)
First_import_jump = +1ECE3 (00C1ECE3 on my machine)
Second_import_jump = +1F71D (00C1F71D on my machine)
Jumps_redirection = +1E457 (00C1E457 on my machine)
To make dump we need to break on jumping to leader dll (0066CF71) , pass three times that internal integrity check (+1FEE8 from loader base) and then place breakpoints on Code_relocation, First_import_jump, Second_import_jump and Jumps_redirection where we need to inject that code. We must leave breakpoint on Internal_check. Then we must stop on every place and change all jumps, values and ijnect code like described before. After that, we will break on Internal_check for the last time. Then we need to undo all changes in loader code (jus select whole section and undo changes) and pass Internal_check for the last time. Continue to that RETN described before that should throw us to stolen code. But something happended and that RETN will lead to wrong address (to nowere , something like F453CDE5). I don't know reason for this, but it isn't important if you already know where stolen code starts. Go there and put new origin there and that's it. Break on fasle OEP, dump file , run ImpREC. In ImpREC use "Trace Level1" to find invaid imports. There should be ~10 invalid ones. Those are emulated API's. I didn't cut them, instead I saved import tree to hard disk.
I spend some time finding those API's, tracing trough original program and looking in some other Delphi programs. I managed to find them all:
Some are repeating. This one LockResource it seams that it doesn't exits on XP because it uses SetHandleCount (I have no idea :-?). What I have done is, I just wrote missing one in saved import tree. Then I load it in ImpREC and fixed dump. After that I added new section and placed stolen OEP's code and set OEP to be there in LordPE. And that's it :)
8. Final words
I sad that I will describe inline patching, but I have no will for that after all this writing. unpacking this protector was very time consuming so I wrote two scripts that can help you. First script will find where is stolen code and OEP. Remember those values because second script that fixes imports needs that information. So, run first one, then restart an use second one. I also include Import_Tree.txt so you can fix all imports.
Protector has trial options which can be easily defeated. Using Regmon you can find where trial info is stored. Breaking on RegCreateKeyExA you can find where is procedure that checks trial limitations. Protector desn't check PE header so you can add new sections which makes inline patching easier. I don't know did I forgot something, but I guess that is all.
Sorry for mistakes in tutorial or in spelling.
Greets to all good people on biw reversing, arteam and crackmes.de. See you in the next tutorial :)