Log in

View Full Version : Unpacking Dlls with Relocations


zacdac
June 12th, 2002, 15:28
G'day..

I’m seeking some help with unpacking dll’s and restoring their relocations.

I have no problem unpacking an exe/dll at a fixed image base.
However I have never seen any tutorials/information on how to dump/reconstruct the relocations.

I have put together a very simple project. It consists of an executable and a dll. The exe loads the dll at runtime and calls one of the dlls exported functions, which displays a messagebox.
The dll is packed with upx to keep things simple.

Both the exe and dll have an imagebase of 00400000 so that the dll will be forced to use an alternative imagebase when it is loaded, and therefore use the relocations table.

I read one post that suggested you do the following:

1) dump the dll using is default imagebase.
2) dump the dll after the sections are unpacked but before the relocations are performed.
3) fix the PE header to restore the relocations table.

Task 1) can be done by converting the dll to exe (note: you have to modify the first jnz in the upx unpacking runtime in order for it to unpack.) and then dump the dll as normal.

Task 2) I have tracked the code and think I have found where the code is unpacked before the relocations are performed. In the upx unpacking runtime, about half way is a “pop esi” which is jumped to after the code is unpacked.

The next half of the routine reconstructs the linked address in the dll (the imports first and then the relocations).

I assume UPX has to do this because the packed dll has no relocations, so the runtime needs to uncompress the .rloc section and then perform the task that the OS loader would normally perform.

Task 3) Well this is where I am struggling.

Can somebody let me know if it is possible to unpack a dll with the relocations ? If yes then I am hoping that by putting together some simple files, that somebody can demonstrate the technique. Then I can put together a nice little tutorial to fill the void.

Thanks,

Zac

nikolatesla20
June 12th, 2002, 15:56
Maybe I will look at this sometimes, but I thought :

Most packers dont waste time with the relocation that I've seen. It's packed, yes, but once the DLL is in mem you should be able to just dump it, and usually the reloc's wont be mucked with, like IAT tables usually are in EXE's with most packers. I don't think I've seen many packers actually mess with the relocation section.

Mainly the only thing you will have to be sure of is the DLL header has the correct relocation info, like for example where the relocations are.

-nt20

Lbolt99
June 12th, 2002, 21:11
Hi,

I got my first try at unpacking a DLL with WebsnatcherIE, a simply IE plug-in. The DLL is protected with ASprotect 1.2.

It was almost the same as unpacking an EXE file. There are a couple of key exceptions, concerning loading the .DLL file and also if patches need to be made.

What you want to try to do is make sure the DLL loads are image base 0x10000000. I did it by doing a clean bootup with nothing running in the background. That way, the WEBBND32.DLL wouldn't relocate when I loaded it, so the relocation table is un-modified by windows when loading the dll.

Proceed as normal as if you are unpacking an ASPR .exe file...

dump at OEP, fix iat, paste, etc..

It should work at this point. But beware that if you have to patch any location in the dll file that corresponds to a relocation entry in the reloc section, you have to modify the relocation table to accomodate. Example:

[Indirect call] - courtesy of ASprotect

The values for this indirect call are processed in the reloc table.

When you patch it to the direct call, it no longer needs to be relocated! So you have to modify the relocation table to fix that.

cyberheg
June 12th, 2002, 21:53
I've unpacked alot dll's and the follow is what I do and hopefully it will give you some hints on how to continue. I apologize that because of lack of time I didn't look at your target but as you pointed out I also write a loader for my target dll's.

First you need to make sure it loads at the prefered imagebase. That is essential to a good file dump because else the data will be relocated at another imagebase.

At the buttom of this text is pasted the code I use for this kinda tasks. The code is rather simple and stupid however it works.

Ok so here goes:

1. Load the dll using this or your own code at the prefered imagebase.

2. Dump it just as you do with a exe file. You need to get inside the dll ofcourse and there are ways in every packer to easily get inside them by using breakpoints. Assuming you got the code, data section etc. dump them like usually and fix the import table.
Nothing new here.

3. I usually use IDA to see what kinda errors it gives on the halfdone file. This is good for showing what kinda problems are left. At this point you need the relocation information.
This is usually stored in a section called .reloc like you pointed out yourself. So you need to dump this section from the memory. In the targets I've looked at the reloc section was remapped so it overlapped the loader (of the packer) section which made a big mess out of it so for me it was easier to just dump it again and paste it into it's place.

Now you must fix the data directory entry called Base relocation. The address of it is RVA of the section which contains the reloc information and the size I dig out with a hexeditor in the following way:
Count the bytes from the very start to the very end of the dump you made. Sometimes the relocation doesn't work in win2k properly while it works in win98. I never found out why but in these cases I solved it by making the size of the relocation data which should be stored into the base relocation directory to 2 bytes bigger then the original count of the bytes.

Now you are ready for testing it.
First I load the stuff into IDA to make sure there are no obvious bugs of my part. Then I load the dumped dll with the code below and see if LoadLibrary returns a valid pointer.
After this you should test if the relocation works. The easiest way to do this is to make a copy of the dumped dll (which you just tested) and load it as a 2nd instance. This will for sure force relocation and thereby you test if everything works. If you set the address and size correctly in the data directory of the PE everything should work out fine.
If not I allready gave suggestion what could be done.
For these tasks I allways start with win98 since it's less picky on errors and if it works I continue to test it on Win2k.

Hopefully this is helpful to you. If you got more questions just ask.

// CyberHeg

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

int ((__cdecl *myfunctptr)(void));
int main()
{
HANDLE hInstance, hInstance2;
FARPROC procptr;
int retnum = 0;
int i;
hInstance = LoadLibrary("file1";
if (hInstance == NULL)
{
printf("Could not load dll: %d\n", GetLastError());
exit(1);
}
// system("pause";
hInstance2 = LoadLibrary("file2";
if (hInstance2 == NULL)
{
printf("Could not load dll: %d\n", GetLastError());
exit(1);
}
/*
procptr = GetProcAddress(hInstance, "test";
if (procptr == NULL)
{
printf("Could not get entrypoint\n";
exit(1);
}

myfunctptr = (int (__cdecl *)(void)) procptr;

retnum = (*myfunctptr) ();
*/
system("pause";

FreeLibrary(hInstance);
FreeLibrary(hInstance2);

return (0);
}

zacdac
June 13th, 2002, 06:05
Thanks for the Replys..

Some observations, and please correct me if have got it wrong.

Looking at UPX...

>> Messing with the relocations section

Logicaly packers could handle relocations two ways.

Remember that by the time the packer's loader is executed, the dll is already loaded in memory and as such the OS can not perform the relocations. Hence the packer's loader must perform this task itself.

1) The packer can uncompress the relocation table to memory intact, and then use the table as the basis for applying the relocations

2) The packer when compressing the relocations table can convert it to it's own format (different from the PE format for relocations) and then when the uncompressing the dll at runtime, it uses it's own format as the basis for applying the relocations.
A packer may choose this option because it is more efficient

This explains why some packers do not do dlls. A dll is more complex than an exe because it has to deal with the relocations issue.

After tracing through the UPX loader code it is seems that UPX performs option 2 above. As such the relocations table is never loaded into memory in it's original format. This means you can not dump it (because it doesn't exist) and hence you can not restore it.

I imagine that the only way to restore the original relocation table would be to convert the UPX relocation table to a PE relocation table.

I have dumped the UPX relocation table, however it is nothing like the PE relocation table. I haven't looked at other packers yet, but some may perform option 1 above but I suspect that most use option 2. Maybe not. From the discussion it would appear that ASprotect restores the relocations table.

Interestingly with UPX, the section table is completely restored in memory.


Zac

zacdac
June 13th, 2002, 06:24
G'day

Attached and below are the views of the relocations table from file and from memory of the packed and non packed files.

Zac



Upx relocations table in Memory
======================
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F

00406300 37 3D 3D 53 3D 3D 34 37 F0 A1 01 0A 0F 0F 14 32 7==S==47ð¡.2
00406310 0A 0F 0F 14 2E 08 24 19 20 0E 0B 2F 19 06 0E 46 ..$  /F
00406320 58 62 CF AD 10 07 2B 2E 3F 12 61 1A 29 26 06 0B XbÏ_+.?a)&
00406330 06 0B 07 A1 35 0B 06 B6 12 0D 16 18 14 00 50 45  ¡5 ¶..PE
00406340 00 00 4C 01 04 00 39 30 00 00 00 00 00 00 00 00 ..L.90........
00406350 00 00 E0 00 0E 23 0B 01 02 34 7A 12 00 00 00 02 ..à.# 4z...
00406360 00 00 58 01 00 00 10 19 00 00 00 10 00 00 00 30 ..X........0
00406370 00 00 00 00 40 00 00 10 00 00 00 02 00 00 04 00 ....@........
00406380 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 60 ..............`
00406390 00 00 00 04 00 00 00 00 00 00 02 00 00 00 00 00 ..............
004063A0 10 00 00 20 00 00 00 00 10 00 00 10 00 00 00 00 .. ..........
004063B0 00 00 10 00 00 00 70 45 00 00 56 00 00 00 00 40 .....pE..V....@

Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F

Relocations table in unpacked file
========================
00002000 00 10 00 00 98 00 00 00 6C 30 72 30 7E 30 B3 30 ....˜...l0r0~0³0
00002010 10 31 64 31 B8 31 0C 32 4B 33 91 33 C9 33 1D 34 .1d1¸1.2K3‘3É3.4
00002020 71 34 B5 34 EC 34 29 35 66 35 B9 35 F6 35 33 36 q4µ4ì4)5f5¹5ö536
00002030 67 36 9E 36 3F 38 49 38 58 38 67 38 7B 38 AD 38 g6ž6?8I8X8g8{8_8
00002040 B7 38 C6 38 D5 38 E9 38 43 39 5C 39 7C 39 8A 39 ·8Æ8Õ8é8C9\9|9Š9
00002050 95 39 C4 39 DD 39 E3 39 F1 39 37 3A 8F 3A C0 3B •9Ä9Ý9ã9ñ97:?:À;
00002060 6D 3C 84 3C DD 3C 1C 3D 2E 3D D2 3D FE 3D 0F 3E m<„<Ý<.=.=Ò=þ=.>
00002070 17 39 F1 3A 7D 3C AF 3C A9 3D F8 3D 09 3E 1A 3E .9ñ:}<¯<©=ø=.>.>
00002080 21 3E 1F 39 8F 3D C2 3E F7 3E 02 3F 08 3F BE 3F !>.9?=Â>÷>.?.?¾?
00002090 F3 3F D0 3F DD 3F 00 00 00 20 00 00 0C 00 00 00 ó?Ð?Ý?... ......
000020A0 0B 30 1F 30 00 00 00 00 00 00 00 00 00 00 00 00 .0.0............

Relocations table in memory of unpacked file
===============================
00405000 00 10 00 00 98 00 00 00 6C 30 72 30 7E 30 B3 30 ...˜...l0r0~0³0
00405010 10 31 64 31 B8 31 0C 32 4B 33 91 33 C9 33 1D 34 1d1¸1.2K3‘3É34
00405020 71 34 B5 34 EC 34 29 35 66 35 B9 35 F6 35 33 36 q4µ4ì4)5f5¹5ö536
00405030 67 36 9E 36 3F 38 49 38 58 38 67 38 7B 38 AD 38 g6ž6?8I8X8g8{8_8
00405040 B7 38 C6 38 D5 38 E9 38 43 39 5C 39 7C 39 8A 39 ·8Æ8Õ8é8C9\9|9Š9
00405050 95 39 C4 39 DD 39 E3 39 F1 39 37 3A 8F 3A C0 3B •9Ä9Ý9ã9ñ97:?:À;
00405060 6D 3C 84 3C DD 3C 1C 3D 2E 3D D2 3D FE 3D 0F 3E m<„<Ý<=.=Ò=þ=>
00405070 17 39 F1 3A 7D 3C AF 3C A9 3D F8 3D 09 3E 1A 3E 9ñ:}<¯<©=ø=.>>
00405080 21 3E 1F 39 8F 3D C2 3E F7 3E 02 3F 08 3F BE 3F !>9?=Â>÷>??¾?
00405090 F3 3F D0 3F DD 3F 00 00 00 20 00 00 0C 00 00 00 ó?Ð?Ý?... ......
004050A0 0B 30 1F 30 00 00 00 00 00 00 00 00 00 00 00 00 00............

Dr.Golova
June 13th, 2002, 16:21
A generic metod is simple - load dll two times with different addresses (make host exe's image base as in dll and dll load to other address). Next simply compare them, find differences and create relocations table. Not too hard.

evaluator
June 13th, 2002, 23:30
also good tools relised for upx-packed files:
UPXFIX

Download it from www.exetools.com
It can unpack files with damaged upx-header,
so it restores reloc-table. (code section use from dump)

Hemm, is not it newbies quistion???

zacdac
June 14th, 2002, 07:13
Thanks again for the replies...

@evaluator - Sorry but you may have not understood my request.
I was after some information about manually restoring relocations section. I was only using upx as an example because it does not restore the orginal relocation table into memory when unpacking. Sorry if manually restoring relocations is a newbies topic ?

@Dr.Golova - Thanks. I think I will have to create a tool that could compare two dump images and then recreate a relocation table. Funny, I imagined it would be a more common problem and that a tool may have already existed.

Zac

evaluator
June 15th, 2002, 17:18
Hello again!

I know only UPX, that mangles RELOC-section.
So self UPX (& UPX-FIX) is good choice for restore RELOC.
(or write your TOOL! Forward thanks

Other packers not mangles RELOC. (aspack-prot)

Also is possible stripping RELOC(mainly in EXEs).
Here is no suggestion.

nikolatesla20
June 17th, 2002, 06:17
evaluator:

Exes in win32 never use relocation, any information in an exe in the reloc can be stripped. ( On an unpacked exe). Maybe a good place to put mod code ?

All the theory points to the possibility of relocation for exe's but in win32 all processes get their own mem space so they never will use it as far as my research has shown.


Also, even with UPX, would not the RELOC be clean after running the program (loading the DLL) and dumping? I think it would have to be. RELOC's do not get modified during a base shift. The addresses they reference get modified. I would think the RELOC section could just be dumped to disk. After all it would need unpacking to memory by the unpacker loader wrapper on the DLL to allow the DLL work at all in the first place.

What do you think?


-nt20

evaluator
June 17th, 2002, 18:54
OK, I agree with you about EXE.

About UPX. When I wrote "UPX mangles RELOC",
I mean: it changes original RELOC with his own formatted RELOC table, so it is useless.

nikolatesla20
June 19th, 2002, 21:26
OK I did a little research on the relocation table, I wasn't all that familiar with it before.

Yep, evaluator, you are right, they are prolly using their own "format" of reloc table with UPX.

Actually, the relocation table is not very complicated to read in a PE file. It should be simple to rebuild it from scratch.

So I agree with Dr. Golova, the best technique would be to load a DLL at two different addresses and compare the differences. Here are my thoughts:

1. Create a program that can somehow load the same DLL twice. You could perhaps have the DLL just be copied and then renamed, and loaded again. Since it has been loaded once already, it will not be able to load a preferred image base, and will have to relocate from the first one.

2. The Handle you get back from LoadLibrary is the ImageBase address of the module. That's right. That's what it is. Last time I checked anyway.

3. Get both imagebases of the two loaded modules and subtract them to find the difference. This is what you will be looking for.

4. NOw, simply scan the memory of both modules for any DWORD values that are different BY THE DIFFERENCE IN IMAGEBASE. These will be your relocated RVA values. When you find a value that differs, log the address you found the difference (MINUS THE IMAGEBASE OF COURSE !). This is the address that needs to be relocated in the table. It should be that simple.

5. Rebuild your own RELOC table with these values, spit out a binary file you can paste in the file to fix it. Note that you can even just make a new section in the dumped PE file for this. Just make sure to change the header data directory to point to the right reloc table.

6. Done.


I might look into making this tool...but I don't know if there will ever be much use for it, how many DLLS have a missing reloc section when packed? Asprotect and Aspack don't seem to do it. Not much demand for a tool, eh..


-nt20

evaluator
June 19th, 2002, 22:37
Hey!

>>Exes in win32 never use relocation

Now I remember ONE

How about NTOSKRNL.EXE!!!!!!!!!!!

It coded for 00400000 base, but because it loads >80000000, so it uses RELOCs.

nikolatesla20
June 20th, 2002, 03:18
Yes you are right evaluator.

EXE image bases can differ between NT and O.S's like Win98. For example, a program must be above a certain base in Win98 in order to run. If you don't have reloc's and you haven't made it above the lower limit base, you are screwed. It won't run.

You are right, I forgot

-nt20