Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Live editing code with gdb

Tags:

assembly

gdb

I do not have extensive experience with gdb, so I am not sure if what I am asking is even possible, but is it possible to edit the code live with gdb?

When running (after hitting a breakpoint), the disas looks like so:

0x080487d8 <+9>:    movl   $0x80485e4,0x1c(%esp)
0x080487e0 <+17>:   movl   $0x8048640,0x20(%esp)
0x080487e8 <+25>:   movl   $0x804869c,0x24(%esp)
0x080487f0 <+33>:   movl   $0x8048719,0x28(%esp)

In an attempt to change the address in one of those instructions, I did this:

set (*0x080487e1)=0x5b870408

But instead of simply changing the address as I expected, the new disas looked like this:

0x080487d8 <+9>:    movl   $0x80485e4,0x1c(%esp)
0x080487e0 <+17>:   (bad)  
0x080487e1 <+18>:   or     %al,(%edi,%eax,4)
0x080487e4 <+21>:   pop    %ebx
0x080487e5 <+22>:   xchg   %al,(%eax,%ecx,1)
0x080487e8 <+25>:   movl   $0x804869c,0x24(%esp)
0x080487f0 <+33>:   movl   $0x8048719,0x28(%esp)

So I have 3 questions: Is what I am trying to do possible? If so, am I doing something wrong? If so, what am I doing wrong and how can I fix it?

like image 482
Jumhyn Avatar asked Dec 28 '22 05:12

Jumhyn


2 Answers

First, I have never used gdb to change the program text like you seem to be doing.

You are changing the value at address 0x080487e1, which is just ahead of your program counter. These values are machine bytecode - e.g. the encoding for movl $0x8048640,0x20.

What's more difficult is that these are of variable length depending on the instruction, so if you corrupt one instruction like you are, it changes the starting address of the next instruction, which means that it will be interpreted as another instruction. This is because you are writing in between instructions.

I'm not sure where you are getting 0x080487e1 or what you are trying to do with it. If you want to chagne the address that movl is using as the first parameter, you will need to know what the movl instruction's command bytecode looks like, and then possibly replace just the part that corresponds to the address value. But then you are stuck with how to get gdb to write to only certain bits (the instructions are not even bit aligned). Sounds possible but hard.

Perhaps you are trying to jump to a different address. You could do this by overwriting with a jump (keep in mind that will be a permanent change for the duration of this program). But the same rules apply as to knowing the format and behavior of jumps.

like image 32
Michael Chinen Avatar answered Jan 12 '23 07:01

Michael Chinen


Is what I am trying to do possible?

Yes, you can change .text of a binary.

Note that this change will only affect current execution; upon run your change will "evaporate" (if you wanted to permanently patch the binary, that's possible as well, but the procedure is different).

If so, am I doing something wrong?

Likely. You didn't tell us what you are trying to change the instruction to.

If so, what am I doing wrong and how can I fix it?

Using (gdb) disas/r will show you actual raw instruction bytes, and will likely make it easier to see what you did wrong. When I use it, I see this:

   0x080483ed <+9>: c7 44 24 1c d0 84 04 08 movl   $0x80484d0,0x1c(%esp)

That is, the address (which you apparently wanted to overwrite) for the instruction above [1] does not begin at &instruction+1, it begins at &instruction+4. Also, you shouldn't reverse the bytes when you ask GDB to write a word (I am guessing you wanted the new address to be 0x0804785b and not 0x5b870408):

(gdb) set *(0x080483ed+4)=0x01020304
(gdb) disas
Dump of assembler code for function main:
   0x080483e4 <+0>: push   %ebp
   0x080483e5 <+1>: mov    %esp,%ebp
   0x080483e7 <+3>: and    $0xfffffff0,%esp
   0x080483ea <+6>: sub    $0x20,%esp
=> 0x080483ed <+9>: movl   $0x1020304,0x1c(%esp)
   0x080483f5 <+17>:    mov    0x1c(%esp),%eax
   0x080483f9 <+21>:    mov    %eax,(%esp)
   0x080483fc <+24>:    call   0x8048318 <puts@plt>
   0x08048401 <+29>:    mov    $0x0,%eax
   0x08048406 <+34>:    leave  
   0x08048407 <+35>:    ret    

[1] It is very likely that your instruction:

0x080487e0 <+17>: movl   $0x8048640,0x20(%esp)

has the same encoding as my instruction:

0x080483ed  <+9>: movl   $0x80484d0,0x1c(%esp)

as they are the "same", and have the same 8-byte length, but as FrankH pointed out, there might exist a different encoding of the same instruction. In any case, disas/r will show you all you need to know.

like image 196
Employed Russian Avatar answered Jan 12 '23 06:01

Employed Russian