Quote:
Originally Posted by Kayaker
As far as I know there are no automagic tools to add exports.
|
Heheh, I stand corrected. Nice one Nacho_dj, very nice. Now there's a tool for everything
I thought I might outline how I added an export as an intro to using your potentially very useful tool. I did have a couple of issues with it that I'll mention at the end.
I started with Iczelion's Tutorial #17 dll/exe example
http://win32assembly.programminghorizon.com/tutorials.html
The usedll.exe calls the export TestHello in DLLSkeleton.dll. I recompiled the exe with Masm32 to add another call to an export called NewExport. One could instead hex edit the single original export name to something else (with the same number of letters) for simple testing purposes.
In the dll I wanted to duplicate the existing MessageBox example, but with a new caption and text. I needed to add new code and data to the file before adding a new export entry so I could point to the proper RVA for the function. I added 2 new sections with CFF Explorer and decided to fill them with created opcode data (Add Section - File Data), rather than creating blank sections and filling them later.
For the new data section I used a hex editor to create a file with two very uninspired text strings separated by 00's:
Code:
00000000 4E 65 77 20 43 61 70 74 69 6F 6E 20 4E 65 77 00 New Caption New.
00000010 54 65 78 74 00 Text.
For the new code section I took the existing opcodes from the original function:
Code:
10001070 TestHello proc near
10001070 6A 00 push 0 ; uType
10001072 68 00 30 00 10 push offset aDllSkeleton ; "DLL Skeleton"
10001077 68 0D 30 00 10 push offset aHelloYouReCallingAFunctionInThisDl ; "Hello, you're calling a function in thi"...
1000107C 6A 00 push 0 ; hWnd
1000107E E8 01 00 00 00 call MessageBoxA
10001083 C3 retn
10001083 TestHello endp
and zeroed out the offset/relative displacement information given in the operands (in red), since they would need to be recalculated once the new code and data sections were in place
Code:
00000000 6A 00 68 00 00 00 00 68 00 00 00 00 6A 00 E8 00 j.h....h....j...
00000010 00 00 00 C3 ....
Now that the two files had been created they could be added to the dll with CFF Explorer as new sections, making sure to use the proper Code Characteristics for code and data.
Now we have a temporary dll with which to calculate displacement values for the push and call instructions. In IDA, View/Subviews/Segments shows us our two new sections:
Code:
.newdata:10005000 4E 65 77 20 43 61+aNewCaption db 'New Caption',0
.newdata:1000500C 4E 65 77 20 54 65+aNewText db 'New Text',0
.newdata:10005015 00 00 00 00 00 00+ align 1000h
.newcode:10006000 6A 00 push 0
.newcode:10006002 68 00 00 00 00 push 0
.newcode:10006007 68 00 00 00 00 push 0
.newcode:1000600C 6A 00 push 0
.newcode:1000600E E8 00 00 00 00 call $+5
.newcode:10006013 C3 retn
The offsets for the push instructions can be taken directly from the disassembly. To correctly reference the MessageBox call we need to calculate the relative displacement to the function call:
Code:
E8 - CALL rel32 Call near, relative, displacement relative to next instruction
10001084 ; int __stdcall MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
10001084 MessageBoxA proc near
10001084 FF 25 00 20 00 10 jmp ds:__imp_MessageBoxA
10001084 MessageBoxA endp
So, (10001084 - 10006013) = -0x4F8F as a signed 32-bit value, or in proper notation, 0xFFFFB071.
A new sequence of opcodes can now be created and used with CFF explorer to give a correct disassembly.
The final step is to use Nacho_dj's tool to add an export entry for the new function, taking note of its RVA, 0x6000. This part is too easy and only takes a sentence to describe
Drag and drop the temporary dll to the tool, Edit Exports, add the new function name, adjust the address of the function to 00006000, click Add, select the Add New Section (.edata) checkbox and save. One small addendum to this - the exports seemingly should be in alphabetical order, so use the arrow buttons to reorder them appropriately.
IDA recognizes the new export and it's ready to go!
Code:
.newcode:10006000 public NewExport
.newcode:10006000 NewExport proc near
.newcode:10006000 6A 00 push 0 ; uType
.newcode:10006002 68 00 50 00 10 push offset aNewCaption ; "New Caption"
.newcode:10006007 68 0C 50 00 10 push offset aNewText ; "New Text"
.newcode:1000600C 6A 00 push 0 ; hWnd
.newcode:1000600E E8 71 B0 FF FF call MessageBoxA
.newcode:10006013 C3 retn
.newcode:10006013 NewExport endp
------------------------------
Here are the two items of note. When I added the second export with your tool I first did them in this order:
TestHello (original export)
NewExport
GetProcAddress in the exe failed to find the second export. I had read that the AddressOfNames array is sorted alphabetically so that a binary search can quickly find a specific string, but I wasn't aware that it was (apparently) an absolute necessity. When I reordered the exports alphabetically GetProcAddress had no problems. Similarly, if I renamed the new export something like ZewExport and kept it in the second position, all was OK.
One small suggestion then if this is truly the case, might be to either reorder the exports alphabetically automatically before saving, or mention it in the help file. If doing that automatically might mess up functions exported by ordinal only, perhaps it's best to leave it up to the discretion of the user.
------------------------------
I also got an error message when saving modifications (like the reordering) to an existing .edata section that the tool previously created. By unchecking the Add New Section box, the RVA of the current .edata section is entered, which is nice, but gave an error after entering the name for the file.
Access violation at address 00403126 in module 'ExportTableTester.exe'. Read of address 00007000.
In my case the RVA of the .edata section was 0x7000. The error occurred in one of those compiler specific functions that redirects calls from a call table:
Code:
403126 8B08 MOV ECX, [EAX] ; eax was 0x7000
403128 FF51FC CALL NEAR [ECX-4]
which was reached from this point in your code:
Code:
00479EEE E8DD59FFFF CALL 0046F8D0 ; access violation in here
00479EF3 84C0 TEST AL,AL
00479EF5 751D JNZ 00479F14
00479EF7 6A30 PUSH 30
00479EF9 6864A44700 PUSH 0047A464 ; "Export Table Tester - Nacho_dj / ARTeam
00479EFE 685CA84700 PUSH 0047A85C ; "Error when saving export table to new f
00479F03 6A00 PUSH 00
00479F05 E822CDF8FF CALL USER32!MessageBoxA
Perhaps I didn't take something into account and did the procedure wrong, but I'd thought I'd mention the error.
Regards,
Kayaker