Adding Code to a PE File
It might be necessary to add code to a program to either crack a protection scheme or to add functionality. There are 3 main ways to add code to an executable:
1. Add to an existing section when there is enough space for your code
2. Enlarge an existing section when there is not enough space
3. Add an entirely new section
Add to an existing section
We need a section in the file that is mapped with execution privileges in memory so simplest is to try the CODE section. We then need an area in the section occupied by 00 byte padding. This is the concept of "caves". To find a suitable cave, look at the CODE section details in LORDPE:
Here we see that the VirtualSize is slightly less than SizeOfRawData. The virtual size represents the amount of actual code. The size of the raw data defines the amount of space taken up in the file sitting on your hard disk. Note that the virtual size in this case is lower than that on the hard disk. This is because compilers often have to round up the size to align a section on some boundary. In the hexeditor at the end of the code section we see:
This extra space is totally unused and not loaded into memory. We need to ensure that the instructions we place there will be loaded into memory. We do this by altering the size attributes. Right now the virtual size of this section is only 29E88, because that is all the compiler needed. We need a little more, so in LordPE change the virtual size of the code section all the way up to 29FFF which is the max size we can use (the entire raw size is only 2A000). To do this rightclick the CODE line and select edit header, make the changes click save and enter.
Once that is done, we have suitable place for our patch code. The only thing we have changed is the VirtualSize DWORD for the CODE section in the Section Table. This could have also been done manually with a hex editor.
Next, we add a small ASM stub that hijacks the entry point and then just returns execution to the original Entry Point. We will do this in Olly.
First we note that the entry point is 0002ADB4 and ImageBase is 400000. When we load the app in Olly the EP will therefore be 0042ADB4. We will add the following lines and then change the entry point to the first line of code:
MOV EAX,0042ADB4 ; Load in EAX the Original Entry Point (OEP)
JMP EAX ; Jump to OEP
We will put them at 0002A300h as seen in the hexeditor above. To convert this raw offset to an RVA for use in Olly use the following formula:
RVA = raw offset - raw offset of section + virtual offset of section + ImageBase
= 2A300h - 400h + 1000h + 400000h = 42AF00h
So load the app in Olly and jump to our target section (press Ctrl + G and enter 42aF00). Press space and type in the first line of assembly and click assemble. The next line should now be highlighted and do the same here.
Now rightclick, select copy to executable and all modifications. Click copy all then a new window will open. Rightclick in the new window and select save file. Now back in LordPE or a hex editor, change the entry point to 2AF00. Now run the app to test it and reopen in Olly to see your new entry point.
Enlarging an Existing Section:
If there is not sufficient space in the text section, you have to extend it. This poses a number of problems.
1. If the section is followed by other sections then you will need to move the following sections to make room.
2. There are various references within the file headers that will need to be adjusted if you change the file size.
3. References between various sections (such as references to data values from the code section) will all need to be adjusted. This is impossible to do without recompiling and relinking the original file.
Most of these problems can be avoided by appending to the last section of the exe file. It is not relevant what that section is as we can make it suit our needs by changing the Characteristics field in the Section Table either manually or with LordPE.
First we locate the final section and make it readable and executable. As we said earlier, the code section is ideal for a patch because its characteristics flags are 60000020 which means code, executable and readable. However, if we are to put code and data into this section we could get a page fault since it is not writeable. To alter this we would need to add the flag 80000000 which gives a new value E0000020 for code, executable, readable and writeable.
Likewise if the final section is .reloc then the flags will be 42000040 for initialized data, discardable and read-only. In order to use this section we must add code, executable and writeable and we must subtract discardable to ensure that the loader maps this section to memory. This gives us a new value of E0000060.
This can either be done manually by adding up flags and editing the Characteristics field of the Section header with the hexeditor or LordPE will do it. In our example, the last section is resources.
This gives us a final characteristic value of F0000060. Above we see the raw size (on disk) of this section is 8E00 bytes but all of this seems to be in use (the VirtualSize os the same). Now edit these and ad 100h bytes to both to extend the section. The new value is 8F00h. There are some other important values which need to be changed. The SizeOfImage field in the PE header needs to be increased by the same amount from 3CE00 to 3CF00.
There are 2 other fields not shown in LordPE which are less critical; SizeOfCode and SizeOfInitializedData in the OptionalHeader. The app will still run without these being altered but you may wish to change them for completeness. We will have to do it manually. Both are DWORDs at offset 1C and 20 from the start of the PE header.
The values are 0002A000 and 0000DE00 respectively. Add 100h on to these. With reverse bytes the values are: 00 A1 02 00 and 00 00 DF 00. Finally copy and paste 100h of 00 bytes onto the end of the section and save changes. Run the file to test for errors.
Adding a new section
In some circumstances you may need to make a copy of an exiting section to defeat self-checking procedures (such as SafeDisk) or make a new section to hold code when proprietary information has been appended to the end of the file.
The first job is to find the NumberOfSections field in the PE header and increase it by 1. Again, most of these changes can be done by LordPE or manually with an hexeditor. Now, in the hexeditor paste 100h of 00 bytes onto the end of the file and make a note of the offset of the first new line. In our case it is 00038200h. This will be the start of our new section and will go in the RawOffset field of the section header. While we are here, it is probably a good time to increase SizeOfImage by 100h bytes.
Next we need to find the section headers beginning at the offset F8 from the PE header. It is not necessary for these to be terminated by a header fill of zeros. The number of headers is given by NumberOfSections and there is usually some space at the end before the sections themselves start (aligned to the FileAlignment value). Find the last section and add a new one after it.
The next thing we need to do is decide which Virtual offset / Virtual Size / Raw Offset and Raw Size our section should have. To decide this, we need the following values:
Virtual offset of formerly last section (.rsrc): 34000h
Virtual size of formerly last section (.rsrc): 8E00h
Raw offset of formerly last section (.rsrc): 2F400h
Raw size of formerly last section (.rsrc): 8E00h
Section Alignment: 1000h
File Alignment: 200h
The RVA and the raw offset of our new section must be aligned to the above boundaries. The Raw Offset of the section is 38200h as we said above (which luckily fits with FileAlignment). To get the VirtualOffset of our section we have to calculate this: VirtualAddress of .rsrc + VirtualSize of .rsrc = 3CE00h. Since our SectionAlignment is 1000h we must round up to the nearest 1000 which makes 3D000h. So lets fill the header of our section.
The first 8 bytes will be Name1 (max. 8 chars e.g. "NEW" will be 4E 45 57 00 00 00 00 00 (byte order not reversed)
The next DWORD is VirtualSize = 100h (with reverse byte order = 00 01 00 00)
The next DWORD is VirtualAddress = 3D000h (with reverse byte order = 00 D0 03 00)
The next DWORD is SizeOfRawData = 100h (with reverse byte order = 00 01 00 00)
The next DWORD is PointerToRawData = 38200h (with reverse byte order = 00 82 03 00)
The next 12 bytes can be left null
The final DWORD is Characteristics = E0000060 (for code, executable, read and write as discussed above)
The first 8 bytes will be Name1 (max. 8 chars e.g. "NEW" will be 4E 45 57 00 00 00 00 00 (byte order not reversed)
The next DWORD is VirtualSize = 100h (with reverse byte order = 00 01 00 00)
The next DWORD is VirtualAddress = 3D000h (with reverse byte order = 00 D0 03 00)
The next DWORD is SizeOfRawData = 100h (with reverse byte order = 00 01 00 00)
The next DWORD is PointerToRawData = 38200h (with reverse byte order = 00 82 03 00)
The next 12 bytes can be left null
The final DWORD is Characteristics = E0000060 (for code, executable, read and write as discussed above)
Save changes, run to test for errors and examine in LordPE
No comments:
Post a Comment