|
ARTeam Tutorial by Shub-Nigurrath Visit:
http://cracking.accessroot.com
|
http://forum.accessroot.com Beginner tutorial #4: unpacking and patching, a more complex case v.1.1 |
| Information | A little tutorial which continues the beginner series started by Gabri3l with some more explanations on an a program packed with aspack, IAT details and the Olly selfextracting function. |
| Target | Super Video Joiner 1.8.0 |
| Available |
http://www.witcobber.com/ or http:/www.intechhosting.com/~access/ARTeam/tools/superjoiner_180.exe |
| Tools | OllyDbg 1.10 (HideDebug and OllyDump plugin), Import Reconstructor 1.6, Diablo2oo2 Universal Patcher |
| Protection | AsPack 2.12 with crippled IAT, Serial Protection |
| level | Beginner |
| Category | patching |
| Author(s) | Shub-Nigurrath Feb 2005 |
| Requirements | Windows XP, Firefox 1.0 and above for best viewing & printing |
|
1. Introduction
|
|
In this tutorial I will (ab)use another little program protected with AsPack, but which cannot be unpacked with the same method Gabri3l told in his already mentioned third tutorial. The target is Super Video Joiner, a nice program useful to join different videos into an unique final one, also DivXs. As we will see later on, this target has a different Import Address Table -IAT- format which will require a little more advanced use of Import Reconstructor. I will also show you how to tell Olly to automatically unpack self-extracting applications (such those protected with aspack, upx or similar but not with asprotect, armadillo etc). The patching of the unpacked application is indeed, once dumped, very easy and will be covered in a few steps. Lastly I will concentrate on the creation of a smart patch which will, hopefully, be valid for future versions: Gabri3l shown you how to use Dup (Diablo2oo2 Universal Patcher) using the Offset Patch, I instead will show you how to use the Search and Replace tab... So, fasten your seatbelts ;-) |
|
2. Unpacking the
program
|
|
By the way, PEiD is not always 100% correct and sometimes report wrong results. Its authors for this reason included the possibility to use an external signature database, an external file inside its installation folder, called userrdb.txt. This file contains all the additional signatures not already included into PEiD. These signatures are usually posted in the forums around, even our one, and you might take time to collect some of them to improve your PEiD accuracy. PEiD installer install a sample userdfb.txt file with no meaningful things inside, so often you need to find a real one around.
Anyway our case is very simple and AsPack is recognised by PEiD easily. You should already know that AsPack is a program's packer, not a program's protector, so it's main target is to reduce the whole exe image file's size, rather than to protect it. So its main characteristic is to be "re-entrant", which means that when the unpacking code finishes to unpack the program into the memory, it doesn't leave any trace and the program appears in memory as nothing happened (see also Gabri3l tutorials). This lead to the method suggested by Gabri3l in his tutorial, which consists in placing an hardware breakpoint on Dword on the stack, just after the first PUSHAD. On the other hand protectors like AsProtect (of the same author of AsPack), instead do several things to the original executable's code and are "not re-entrant"; also when the program is uncompressed in memory, ready to execute, it's code has been widely modified (its IAT modified so as to not rebuild it easily, its instructions modified to not follow the program's flow easily and so on).
Let Ollydbg unpack the program for us In this document I will follow instead an alternative way, which is already implemented into OllyDbg and which is not so much known/used. Goto into the OllyDbg settings and set them as in the picture below:
OllyDbg has an automatic Self Extractors (SFX) feature, which does the a trick similar (more complex actually) to what Gabri3l explained you. This trick is valid as I told for all the "re-entrant" program's packers or generally for all the self extractor executable. Ollydbg is able to do all the work for you and to stop at the right place! Once you set your settings as above you are ready to load your target into Ollydbg (in this case the program is videojoiner.exe). There's not need to close and reopen Olly, it's enough to relauch the program, e.g. using CTRL-F2 if it was already opened. Usually Ollydbg would have stopped at the first instruction of the AsPack unpacker (see below), which was a PUSHAD
004F8001 > 60 PUSHAD
As you can see Olly also reports in the status bar a statistic of the work done:
If you haven't still done it press a CTRL-A to reanalyze the program, and to see clearly that we are in the real OEP of the program. A note about Ollydbg: Ollydbg stores away (into the UDD file) the original OEP just found, so the next time we will launch the same program the OEP will be immediately found and Ollydbg will report that the SFX entry point (aka the OEP) has been "learned":
As you can see the point where we stopped this time is the same we would have obtained doing the process manually! Well, a little bit of work skipped!
Dumping the Process and Fixing the IAT First of all dump the program using OllyDump, uncheck Rebuild Import and take note of the OEP. In this case is: AF0A0.
I called the dump file, with a name of fantasy, dump.exe. Now open Import Reconstructor 1.6 and open the process you are debugging from the processes list. I'll do it brief hoping you are already accustomed to this program, so the picture reports everything needed, and the number are the steps to follow.
As you should already know this is the address where
ImpRec beleives the IAT is (the IAT has a fixed
structure so it's easily recognized by ImpRec). We need to instruct ImpRec to find on it's own the APIs in the memory space of the process in a different way!
See how.. Right click on the white space of the interface, and you should get this contextual menu:
Understanding what ImpRec will do This is the situation you should see now:
004AF0A0 /. 55
PUSH EBP ; Real entry point of SFX code Look the call: it is like CALL videojoi.00406C94, where 00406C94 is the called address. At the called address this what we find:
00406C94 $-
FF25 04474B00 JMP DWORD PTR DS:[4B4704] ;
user32.FindWindowA So let try to summarize: we have a CALL to an address (004AF0D6), which contains a JMP to another address (004B4704), so we can see the first called address as a memory pointer to the real called address, which in assembler is as an indirect call. Its syntax generally is: or rather, using ImpRec notation, CALL [X].. What the ImpRec is still asking to you? "Get CALL [X] Scheme"... For example when a registry contains an address of a subroutine to call the ASM instruction will be CALL [EAX], if EAX is the register. But let take a short break to dig a little this specific argument, I think that could be interesting to know some details about how the calls to imported functions are generated from the compiler and why. Let's examine what the call to an imported API looks like. There are two cases to consider: the efficient way and inefficient way. In the best case, a call to an imported API looks like this: CALL DWORD PTR [0x00405030] If you're not familiar with x86
assembly language, this is a call through a function
pointer. Whatever DWORD-sized value is at 0x405030 is
where the CALL instruction will send control. In the
previous example, address 0x405030 lies within the IAT. CALL 0x0040100C ........ 0x0040100C: JMP DWORD PTR [0x00405030]In this situation, the CALL transfers control to a small stub. The stub is a JMP to the address whose value is at 0x405030. Again, remember that 0x405030 is an entry within the IAT. In a nutshell, the less efficient imported API call uses five bytes of additional code, and takes longer to execute because of the extra JMP.
You're probably wondering why the less efficient method
would ever be used. There's a good explanation. Left to
its own devices, the compiler can't distinguish between
imported API calls and ordinary functions within the
same module. As such, the compiler emits a CALL
instruction of the form CALL XXXXXXXXwhere XXXXXXXX is an actual code address that will be filled in by the linker later. Note that this last CALL instruction isn't through a function pointer. Rather, it's an actual code address. To keep the cosmic karma in balance, the linker needs to have a chunk of code to substitute for XXXXXXXX. The simplest way to do this is to make the call point to a JMP stub, like you just saw. Where does the JMP stub come from? Surprisingly, it comes from the import library for the imported function. If you were to examine an import library, and examine the code associated with the imported API name, you'd see that it's a JMP stub like the one just shown. What this means is that by default, in the absence of any intervention, imported API calls will use the less efficient form. Logically, the next question to ask is how to get the
optimized form. The answer comes in the form of a hint
you give to the compiler. The __declspec(dllimport)
function modifier tells the compiler that the function
resides in another DLL and that the compiler should
generate this instruction CALL DWORD PTR [XXXXXXXX]rather than this one: CALL XXXXXXXXIn addition, the compiler emits information telling the linker to resolve the function pointer portion of the instruction to a symbol named __imp_functionname. For instance, if you were calling MyFunction, the symbol name would be __imp_MyFunction. Looking in an import library, you'll see that in addition to the regular symbol name, there's also a symbol with the __imp__ prefix on it. This __imp__ symbol resolves directly to the IAT entry, rather than to the JMP stub. So what
does this mean in your everyday life? If you're writing
exported functions and providing a .H file for them,
remember to use the __declspec(dllimport) modifier with
the function: __declspec(dllimport) void Foo(void);If you look at the Windows system header files, you'll find that they use __declspec(dllimport) for the Windows APIs. It's not easy to see this, but if you search for the DECLSPEC_IMPORT macro defined in WINNT.H, and which is used in files such as WinBase.H, you'll see how __declspec(dllimport) is prepended to the system API declarations.
When you press OK in the ImpRec's dialog box discussed above, the program starts to work, and the final result is something which looks like below:
To eliminate them simply right click on one of them and select "Cut Chunk(s)" (see the contextual menu shown few pictures above). Press "Show Invalid" again and this time you shouldn't get any invalid entry. The ImpRec log window reports "Congratulation! There is no more invalid pointers, now the question is: Will it work?:-)"
Press Fix Dump and we will answer soon to this question ;-) Obviously the answer is yes, it
works! |
|
3. Patching the
Program
|
|
Now we have a working dump and we are ready to happily patch the application. First of all study the protection: there are three limitations to the program, it cannot join more than two files, when you exit there is a messagebox and you cannot enter any registration code you like. All these limitations have very clear Bad Boy messages, which are essential grips to start reversing with Olly. From earlier beginner tutorials of this series and of ARTeam's tutorials collection, you should have learnt that a Bad Boy is a great place from where to find references to the code to patch, you should also know how to search referenced strings in OllyDbg. Following this method I found these three points where to patch the application. I will report them briefly without commenting them too much, because are very simple indeed (just some jmps patching). I also anyway reported the referenced strings I used to find the right point. Patch1 Patched Code: Patch2 Patched Code: Patch3 Patched Code: You have done it! I hope you understood what I simply pasted here, (sorry, but it's useful to make the whole tutorial shorter). From Ollydbg save the applied patches to a program and call it for exampl dump.patched.exe, then run it. It works fine with no limitations or
annoying nags and allows to join more than two
sequences.. |
|
4. Creating the
Patcher
|
|
Also this time we will use Diablo2oo2 Universal Patcher to create the patcher, it has an unique feature to be able to patch packed programs and specifically supports AsPack. The final patch so it will be able to work on the original installed file without having to dump it and reducing the distribution weight. Anyway this time we will use a different method to create a patcher, the "Search and Replace". Search and Replace, general
considerations This is DuP Search and Replace form:
You should start entering the original byte pattern in 1, the the new one in 2, press the Add button in 3 and Check occourrence of "Search Bytes" in 4. The finally you shold see your result(s) in 5. By the way, generally speaking if the byte pattern is not unique DuP let you also choose the occourrence number to patch, using the Occourrence box.
Choosing the byte patterns A1 081E4B00 MOV EAX,DWORD PTR DS:[4B1E08] has an op-code equal to A1 (the MOV EAX, DWORD PTR DS:[]), and an operand equal to 081E4B00 (which is 4B1E08 in reverse order). Given this, we are ready to go further, to understand the way to proceed. For the sake of shortness, I will report here again the Patch1 wrote in Section #3 of this tutorial. I will do the complete steps only for this patch and for the other I will only give to you the final results so you can train yourself. Original Code: which in bytes is as follows: 75,14,A1,08,1E,4B,00,83,38,00,74,0A,A1,9C,1E,4B,00,83,38,00,75,12,BA,00,72,4A,00 the yellow part denotes the operands. Well, so cut these things away from the above byte pattern and substitute them with a couple of * 75,**,A1,**,**,**,**,83,38,**,74,0A,A1,**,**,**,**,83,38,**,75,**,BA,**,**,**,** Thinking to operands a little more I can see that we can leave in place some of them, like the first, equal to 14, which is an offset to a relative jmp destination (means 14 bytes forward) because I can suppose that if the code changes it's position in next releases it will do as a whole block so the relative offset of 14 bytes is small enough to be sure that even the destination bytes of the jmp will be there. The operand of the instruction at 004A712A which is 00, is also for sure a think that will be still here in future releases. So this lead to our final search string: Original byte sequence: The concept is: do not include offsets too far away from the peice of code you are going to patch, the other operands can be left. The patched code is the follow: leads to this string instead:
Patched byte sequence: Well, enter them into Dup Note: if you right click on the edit field 1 or 2 DuP it will open a contextual menu which allows to paste the search pattern without having to manually insert it (CTRL-C won't work). In 5 select the byte pattern you added and press the button in 4 to get this result:
To make the story shorter the byte patterns of the other two left patches are: Patch2:
Original byte sequence: Patch3:
Original byte sequence: I think you might now rebuild how I got them. Finally Diablo2oo2 Universal Patcher should look like below:
You are ready to create the patch, remember to tag the "Target is packed" checkbox, save the project and create the patch. You are now ready to test it! Of course (should) work. |
|
5.
Conclusions
|
|
Lesson Learnt I realize each time that, if someone wants to get things basic, there's a lot to write and a lot of snapshots to take. So simpler tutorials are those which take more time, anyway I write them also hoping to help new RCE saplings grow.. ^__^ I hope you improved your skill with ollydbg and with what happens under the cover. I hope also you understood that even simple things such as AsPack could be a little more complicated of how a single tutorial drove you to suppose. I also hope you started to understand that RCEing most of the times means analyzing things under a different point of view and be open minded.
have phun! |
|
6. Greetingz
|
|
[MAIN TEAM]
|