Rebuilding and cracking Neolite's Pecomp.DLL file
I've read a lot of tutorials on the web on the subject of reverse engineering, and I thought it would be nice to work on something I have very little knowledge about and give back a little something to those who have written essays, and for those who are thinking about it. I choose Neolite because I had tried long ago to unpack a program packed with it, and couldn't. I gave it another go recently, and it remains a challenge no longer. I'm not going to write an essay about it, because if you can unpack the pecomp.dll file, then you should be able to unpack any Neolite packed .exe file.
I've had Neolite on my list of things I wanted to work on for a long time now. Until recently, I didn't have enough knowledge to work on it. I've unpacked a few executables in the past, but never a .dll file. From a posting on one of the reversing message boards, I learned a little how the .dll file works. I know that inside your .exe file, you use Loadlibrarya to load the file, and Getprocaddress to find the address of the function you wish to call in the .dll file. But how do you compress or uncompress a dll file, if all I am doing is calling functions? There is code that starts when the executable is run. This code first uncompresses the sections then jumps to the code that would have been run originally, except that it was compressed. It's similar to an executable file, so that means that we need to find the OEP. The nice thing about this compresser is that a few lines down from the start of the compresser there is:
4xxxxxx JMP EAX <-- Original Entry Point
We will need to write the value of EAX down for use later. Now what I did prior to working in Soft-ice, was to get some information about the file, such as raw size, raw offset, etc.
Section Table - Before ---------------------- v/a v/s r/o r/s characteristics --- --- --- --- --------------- BEGTEXT 00001000 00015C00 00000000 00015C00 C0000080 DGROUP 00017000 00004000 00000000 00004000 .bss 0001B000 00000000 00000000 00022600 .idata 0003E000 00000600 00000000 00000600 .edata 0003F000 00000200 00000000 00000200 Oreloc 00040000 00001000 00000400 00000200 .rsrc 00041000 00022E00 00000600 00000600 .neolit 00064000 0000612C 00000C00 00001C00 .reloc 0006B000 000000D8 00002800 00000200
Notice how for the first four section we have no raw offset, we will have to remember to adjust this after we are done dumping our unpacked sections and re-creating our new file.
So I wouldn't have to worry about using the test version of Neolite, I copied my unpacked .exe file to whatever name I wanted and with hiew changed all the occurances of pecomp.dll to say qecomp.dll. You will find two occurances. Then I copies pecomp.dll to qecomp.dll.
This may not be the best way, but it's the only way I can think of right now. If anyone has a better suggestion I would like to know about it. I found the entry point(not the OEP) for qecomp.dll, wrote down the bytes for it -- which are E9 A6 00 00 00. I replaced the E9 with a CC(int 03), and in Soft-ice I turned int 03 checking on by typing:
I then replaced the CC with a E9 again, and adjusted the EIP to where the CC used to be so we can continue on with unpacking the file, with us in control. Once I hit F10 a few times and come to the JMP EAX, which is 43C638 on my machine, I type map32 qecomp in Soft-ice. This shows me where my sections are loaded in at. BEGTEXT starts at 431000, so for out virtual address, we need only to add 30000h to them to find out where each section is. I still use the dumper SDUMP, and looking at 431000 and I have data. I then look at DGROUP - got data, .bss - ?????. I saw this in the executable, and through trial and error saw that the ??? were simple zero's. This is really just temporary space that program uses. I'll have to play with the characteristic and see if I can see the true data, otherwise what I did was wrote a byte to the location that was hidden by ??? and then scrolled through it. Not a great technique but it worked. I copied the data from 431000 with a length of 1A000 to my dumper memory location and hit enter to dumped it. Looking at our sections the first raw offset is at 400, but to make things easier on ourselves for creating the .dll file, lets erase everything from 400 on down on another copy of pecomp.dll. Then let's add C00h bytes of zero's(can be anything) and paste our dump to it. There now we have two sections dumped. Let's add a few more zero's, say 23000h of them for the .bss section. Why not 22600, because our section alignment is 1000h, and it would be easier for us to have the raw offset match the virtual offset, so let's do that. At the end we should have seven unpacked sections to our .dll file, and the last remaining two, which we just need to copy untouched. Now going back in under soft-ice, and having Sdump waiting, we move memory from 43e000 for a length of 26000h bytes. Note: I am dumping multiple sections when possible. Then paste to the end of our dll file we are constructing. Then last but not least past the last two sections in. Yes, we are almost done, but not quite yet.
We need to now fix the header up to reflect our changes. We need to adjust the header to look like the one below and also change the Entry point to be C638. That should be all for unpacking the file. You can try to crack the program yourself, or follow along with the rest of the tutorial.
Section Table - After --------------------- v/a v/s r/o r/s characteristics --- --- --- --- --------------- BEGTEXT 00001000 00015C00 00001000 00015C00 C0000080 DGROUP 00017000 00004000 00017000 00004000 .bss 0001B000 00000000 0001B000 00022600 .idata 0003E000 00000600 0003E000 00000600 .edata 0003F000 00000200 0003F000 00000200 Oreloc 00040000 00001000 00040000 00000200 .rsrc 00041000 00022E00 00041000 00000600 .neolit 00064000 0000612C 00064000 00001C00 .reloc 0006B000 000000D8 0006B000 00000200 Cracking the nag ----------------
The nag that appears at the beginning is created by a messageboxa, and allows you to run the program, or connect to the Neoworx web page. I want to run it, but I don't want the hassle of clicking yes or no. Cracking it on our compressed file is simple, but where does the code come from that is inserted into our compressed file? I at first hunted a little in the .exe file, but that would be a little to easy. And I was right, it's not there; it's in the pecomp.dll file, actually residing in the .rsrc section. The code is just copied over to a memory location that will be used to write the first chunk of data for our new compressed file. How do we know this? Write down the call bytes and cmp bytes in our file, then do a search in Soft-ice. All we have to do is overwrite the call with a jmp statement. Actually we need to go two more lines up in the code and overwrite the two pushes. Becuase of testing in Soft-ice I replaced the code containing the pushes with 90 E9 9F 00 00 00.
Now try to compress your program, I used notepad, and then run it. No more nag screen!
I think this is a nice essay for people who have a little knowledge about assembly, the PE format, and are just really curious. What makes Neolite a nice stepping stone is the lack of anti-debugging code and how easy it is to uncompress the file without tracing through tons of code.