PDA

View Full Version : How to add a line of assembly? (I have searched)


zambuka42
March 10th, 2008, 02:24
Hello. I would like to insert a line of code (let's say: mov eax, 0). Now, I have searched and found one post that looked helpful, but all the links were dead. Another post I read talked about changing the .code segment and such, but I wasn't sure that it was the same notion of what I'm trying to do. So.. is it a big deal to try and add a line of code... or do I need to find a 'code cave' and re-route the flow of the program to this location and back?

Thanks alot. -b

OHPen
March 10th, 2008, 03:19
Hi,

as you mentioned cave code is a possibility. first you have to insert a jmp to the cave you found right at the place where you want to insert the line of code (you will overwrite some bytes of the original code because of the jmp you have to assemble, so remember that instructions). assemble the code you want to insert into the code cave + the overwritten instructions. tha last thing is to assemble a jmp back to the next valid instruction after that overwritten instruction from the original code.

this is only one of plenty of possibilies. you can also add a new section with your insertion code. you can modify the entry point to allocate space where you store your insertion code. you can store the code in resources, yada, yada, yada.

as you see, you are spoilt for choise

i you don't have to insert a huge amount of code then i would suggest the first method, because its the simplest one.

have fun.

OHPen aka PAPiLLiON

zambuka42
March 10th, 2008, 04:13
thanks for the info. You know, I didn't realize that there is usually (i guess) a large 'cave' area at the end... that is simple enough.

For any other newbies... here is what I did (this is just a random piece of code):

say we have these lines:
Code:
006B8E63 6A 00 PUSH 0
006B8E65 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8]
006B8E68 50 PUSH EAX
006B8E69 A1 C0907A00 MOV EAX, DWORD PTR DS:[7A90C0]
006B8E6E A1 C0907A00 MOV EBX, DWORD PTR DS:[7A90C0]


Now lets say I want to insert a line of code here:
Code:
006B8E63 6A 00 PUSH 0
006B8E65 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8]
<insert> B8 99000000 MOV EAX, 99
006B8E68 50 PUSH EAX
006B8E69 A1 C0907A00 MOV EAX, DWORD PTR DS:[7A90C0]
006B8E6E A1 C0907A00 MOV EBX, DWORD PTR DS:[7A90C0]


I accomplished that by moving everything between the first and last line of that segment to an empty area thusly:

1. First find an empty area... I am using ollydbg, and I simply navigated to the bottom of the code where I found a large area that looked like this:
Code:
006BEFE9 00 DB 00
006BEFEA 00 DB 00
006BEFEB 00 DB 00
006BEFEC 00 DB 00
006BEFED 00 DB 00
006BEFEE 00 DB 00
006BEFEF 00 DB 00


2. This area can be overwritten without consequences (From what I understand). So first we will overwrite this area with the lines we want to move (making sure to include the code you want to add):
Code:
006BEFE9 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8]
006BEFEC B8 99000000 MOV EAX, 99
006BEFF1 50 PUSH EAX
006BEFF2 A1 C0907A00 MOV EAX, DWORD PTR DS:[7A90C0]


3. Now, we'll replace the lines from the original segment with a statement to jump to this new segment (I'll NOP out the excess area for aesthetics):
Code:
006B8E63 6A 00 PUSH 0
006B8E65 E9 7F610000 JMP 006BEFE9
006B8E6A 90 NOP
006B8E6B 90 NOP
006B8E6C 90 NOP
006B8E6D 90 NOP
006B8E6E A1 C0907A00 MOV EBX, DWORD PTR DS:[7A90C0]


4. Finally, we'll add a jump statement at the end of the new segment to return and continue executing the last line of the original segment:
Code:
006BEFE9 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8]
006BEFEC B8 99000000 MOV EAX, 99
006BEFF1 50 PUSH EAX
006BEFF2 A1 C0907A00 MOV EAX, DWORD PTR DS:[7A90C0]
006BEFF7 E9 729EFFFF JMP 006B8E6E


5. So in summation, here is the route that the program now takes when executing the code:
Code:
006B8E63 6A 00 PUSH 0
006B8E65 E9 7F610000 JMP 006BEFE9
006BEFE9 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8]
006BEFEC B8 99000000 MOV EAX, 99
006BEFF1 50 PUSH EAX
006BEFF2 A1 C0907A00 MOV EAX, DWORD PTR DS:[7A90C0]
006BEFF7 E9 729EFFFF JMP 006B8E6E
006B8E6E A1 C0907A00 MOV EBX, DWORD PTR DS:[7A90C0]


I know that is a large rundown for such a simple concept.. but hopefully someone will find it useful.

naides
March 10th, 2008, 08:41
Just watch out: The code caves you find, have to exist in the physical file on disk, not only in memory (virtual space).
Also make sure that the cave area is never written/read from, particularly if you place it in any other segment besides the .text (or .code) segment. Otherwise the trick will not work.
Adding "a single line of code", is more an illustrative example. It is almost always possible to get away with the reversing by modifying the code before or after to emulate the effect you would get by adding a single extra line of code (What I mean is that for a single instruction crack, there is almost always an alternative solution somewhere else in the code). Adding lines of code is necessary for more complex, multi-instruction modifications.

zambuka42
March 10th, 2008, 10:39
Thanks for the info naides. I was unaware that cave areas in the .code segment could be written to by the program.. good looking out. As for the necessity of adding code.. I whole-heartedly agree that there is almost always an alternative solution. Sometimes though, it's just less time consuming to add some code (if not a cheap-messy way to go about it).

naides
March 10th, 2008, 12:31
.code segment is rarely written by the program, so it is the safest place to find code caves, but there are exceptions.
Caves in the .data segments and resource sections stand a chance to be written during the normal operation of a program.

Admiral
March 10th, 2008, 13:47
These trailing code caves come into existence because the .code segment's disk image is often (though not always) forced to be a multiple of 0x400 bytes in length, for performance & compatibility reasons. So the worst case scenario would have this condition automatically satisfied after linking, resulting in the production of no code cave. Conversely, the best-case scenario would result in a code cave of 0x3FF bytes being produced. I have seen values of 0x200 and 0x800 also used, and I wouldn't be surprised if others are common - I suspect there's a minimum to this padding size, but understand that it is valid to append almost arbitrarily large amounts of dead data onto a segment.

Anyway, you should also be aware that for short inline patches like this, you can often find or make caves in tighter spots. It's not uncommon for functions to be separated by sequences of INT 3 instructions which will never fire, in theory, so a big enough such area can serve the same purpose. Furthermore, if you have a keen eye for assembly language you can often optimise existing code into smaller opcodes and use the space you've freed up for your own wrongdoings.

Admiral

Kayaker
March 10th, 2008, 14:15
Quote:
[Originally Posted by Admiral;73244]you can often optimise existing code into smaller opcodes and use the space you've freed up for your own wrongdoings.


Heheh, hardcore. Desperate times call for desperate measures?

personmans
March 10th, 2008, 16:20
I've encountered this problem (solution?) before. It seems to come up a lot when working with some of the more useless (registration check) functions. =]

zambuka42
March 10th, 2008, 19:22
Quote:
[Originally Posted by Admiral;73244]...It's not uncommon for functions to be separated by sequences of INT 3 instructions which will never fire, ...if you have a keen eye for assembly language you can often optimise existing code into smaller opcodes and use the space you've freed up for your own wrongdoings.Admiral


Hey thanks for the reply. I've been meaning to look up what the INT 3 instructions were for. That's good to know. As for optimizing the code.. that seems like such a daunting task for my current level of knowledge. I hope I can reach that point though.

Admiral
March 11th, 2008, 04:33
Quote:
[Originally Posted by zambuka42;73255]Hey thanks for the reply. I've been meaning to look up what the INT 3 instructions were for.

As far as I can tell, they're put there for both debugging and performance reasons. The CPU's L1 (?) cache has a better time working with DWORD/QWORD-aligned blocks of code, so it's common for the compiler to pad between functions to reach such a boundary. The INT3 instruction is as good as any, as this padding - although in executable memory - should never be executed and so in the case of an anomaly the debugger will quickly be alerted.

zambuka42
March 11th, 2008, 20:36
right on. thanks for that.