In gdb x86_64 environment, like below example, when I tried to extract field value of $eflags to use as a breakpoint condition element, I got an error.
(gdb) cond 1 ($eflags & 0x200) != 0
(gdb) continue
Continuing.
Error in testing breakpoint condition:
Invalid cast.
[Switching to Thread 1.1]
Ofcourse, when extracting a specific field of $eflags, like p $eflags & 0x200, I got also Invalid cast error.
How to get a specific field from $eflags?
I do not know whether it is related or not, I debug a Rust program.
Environment
uname -a: Linux ubuntuMac 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Ubuntu version: 22.04 LTS
cpu: Intel(R) Core(TM) i5-5250U CPU # 1.60GHz
gdb version: GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Thanks.
p $eflags & 0x200
This doesn't work because:
(gdb) ptype $eflags
type = flag i386_eflags {
bool CF #0;
bool #1;
bool PF #2;
bool AF #4;
bool ZF #6;
bool SF #7;
bool TF #8;
bool IF #9;
bool DF #10;
bool OF #11;
bool NT #14;
bool RF #16;
bool VM #17;
bool AC #18;
bool VIF #19;
bool VIP #20;
bool ID #21;
}
However, you can cast $eflags to int:
(gdb) p $eflags
$1 = [ IF ]
(gdb) p/x (int)$eflags
$2 = 0x202
(gdb) p/x (int)$eflags & 0x2
$3 = 0x2
Related
I'm trying to calculate the base address of the library of a binary file.
I have the address of printf, puts ecc and then I subtract it's offset to get the base address of the library.
I was doing this for printf, puts and signal, but every time I got a different base address.
I also tried to do the things in this post, but I couldn't get the right result either.
ASLR is disabled.
this is where I take the address of the library function:
gdb-peda$ x/20wx 0x804b018
0x804b018 <signal#got.plt>: 0xf7e05720 0xf7e97010 0x080484e6 0x080484f6
0x804b028 <puts#got.plt>: 0xf7e3fb40 0x08048516 0x08048526 0xf7df0d90
0x804b038 <memset#got.plt>: 0xf7f18730 0x08048556 0x08048566 0x00000000
then I have:
gdb-peda$ info proc mapping
process 114562
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x804a000 0x2000 0x0 /home/ofey/CTF/Pwnable.tw/applestore/applestore
0x804a000 0x804b000 0x1000 0x1000 /home/ofey/CTF/Pwnable.tw/applestore/applestore
0x804b000 0x804c000 0x1000 0x2000 /home/ofey/CTF/Pwnable.tw/applestore/applestore
0x804c000 0x806e000 0x22000 0x0 [heap]
0xf7dd8000 0xf7fad000 0x1d5000 0x0 /lib/i386-linux-gnu/libc-2.27.so
0xf7fad000 0xf7fae000 0x1000 0x1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fae000 0xf7fb0000 0x2000 0x1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fb0000 0xf7fb1000 0x1000 0x1d7000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fb1000 0xf7fb4000 0x3000 0x0
0xf7fd0000 0xf7fd2000 0x2000 0x0
0xf7fd2000 0xf7fd5000 0x3000 0x0 [vvar]
0xf7fd5000 0xf7fd6000 0x1000 0x0 [vdso]
0xf7fd6000 0xf7ffc000 0x26000 0x0 /lib/i386-linux-gnu/ld-2.27.so
0xf7ffc000 0xf7ffd000 0x1000 0x25000 /lib/i386-linux-gnu/ld-2.27.so
0xf7ffd000 0xf7ffe000 0x1000 0x26000 /lib/i386-linux-gnu/ld-2.27.so
0xfffdd000 0xffffe000 0x21000 0x0 [stack]
and :
gdb-peda$ info sharedlibrary
From To Syms Read Shared Object Library
0xf7fd6ab0 0xf7ff17fb Yes /lib/ld-linux.so.2
0xf7df0610 0xf7f3d386 Yes /lib/i386-linux-gnu/libc.so.6
I then found the offset of signal and puts to calculate the base libc address.
base_with_signal_offset = 0xf7e05720 - 0x3eda0 = 0xf7dc6980
base_with_puts_offset = 0xf7e3fb40 - 0x809c0 = 0xf7dbf180
I was expecting base_with_signal_offset = base_with_puts_offset = 0xf7dd8000, but that's not the case.
What I'm doing wrong?
EDIT(To let you understand where I got those offset):
readelf -s /lib/x86_64-linux-gnu/libc-2.27.so | grep puts
I get :
191: 00000000000809c0 512 FUNC GLOBAL DEFAULT 13 _IO_puts##GLIBC_2.2.5
422: 00000000000809c0 512 FUNC WEAK DEFAULT 13 puts##GLIBC_2.2.5
496: 00000000001266c0 1240 FUNC GLOBAL DEFAULT 13 putspent##GLIBC_2.2.5
678: 00000000001285d0 750 FUNC GLOBAL DEFAULT 13 putsgent##GLIBC_2.10
1141: 000000000007f1f0 396 FUNC WEAK DEFAULT 13 fputs##GLIBC_2.2.5
1677: 000000000007f1f0 396 FUNC GLOBAL DEFAULT 13 _IO_fputs##GLIBC_2.2.5
2310: 000000000008a640 143 FUNC WEAK DEFAULT 13 fputs_unlocked##GLIBC_2.2.5
I was expecting base_with_signal_offset = base_with_puts_offset = 0xf7dd8000
There are 3 numbers in your calculation:
&puts_at_runtime - symbol_value_from_readelf == &first_executable_pt_load_segment_libc.
The readelf output shows that you got one of these almost correct: the value of puts in 64-bit /lib/x86_64-linux-gnu/libc-2.27.so is indeed 0x809c0, but that is not the library you are actually using. You need to repeat the same on the actually used 32-bit library: /lib/i386-linux-gnu/libc-2.27.so.
For the first number -- &puts_at_runtime, you are using value from the puts#got.plt import stub. That value is only guaranteed to have been resolved (point to actual puts in libc.so) IFF you have LD_BIND_NOW=1 set in the environment, or you linked your executable with -z now linker flag, or you actually called puts already.
It may be better to print &puts in GDB.
The last number -- &first_executable_pt_load_segment_libc is correct (because info shared shows that libc.so.6 .text section starts at 0xf7df0610, which is between 0xf7dd8000 and 0xf7fad000.
So putting it all together, the only error was that you used the wrong version of libc.so to extract the symbol_value_from_readelf.
On my system:
#include <signal.h>
#include <stdio.h>
int main() {
puts("Hello");
signal(SIGINT, SIG_IGN);
return 0;
}
gcc -m32 t.c -fno-pie -no-pie
gdb -q a.out
... set breakpoint on exit from main
Breakpoint 1, 0x080491ae in main ()
(gdb) p &puts
$1 = (<text variable, no debug info> *) 0xf7e31300 <puts>
(gdb) p &signal
$2 = (<text variable, no debug info> *) 0xf7df7d20 <ssignal>
(gdb) info proc map
process 114065
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0x0 /tmp/a.out
...
0x804d000 0x806f000 0x22000 0x0 [heap]
0xf7dc5000 0xf7de2000 0x1d000 0x0 /lib/i386-linux-gnu/libc-2.29.so
...
(gdb) info shared
From To Syms Read Shared Object Library
0xf7fd5090 0xf7ff0553 Yes (*) /lib/ld-linux.so.2
0xf7de20e0 0xf7f2b8d6 Yes (*) /lib/i386-linux-gnu/libc.so.6
Given above, we expect readelf -s to give us 0xf7e31300 - 0xf7dc5000 ==
0x6c300 for puts and 0xf7df7d20 - 0xf7dc5000 == 0x32d20 for signal respectively.
readelf -Ws /lib/i386-linux-gnu/libc-2.29.so | egrep ' (puts|signal)\W'
452: 00032d20 68 FUNC WEAK DEFAULT 14 signal##GLIBC_2.0
458: 0006c300 400 FUNC WEAK DEFAULT 14 puts##GLIBC_2.0
QED.
I have this program:
double t;
main() {
}
On Ubuntu, I run:
% gdb a.out
(gdb) p &t
$1 = (double *) 0x4010 <t>
(gdb) run
Starting program: /home/phan/a.out
[Inferior 1 (process 95930) exited normally]
(gdb) p &t
$2 = (double *) 0x555555558010 <t>
Why did the address change from 0x4010 to 0x555555558010. Is there someway to prevent this?
On Redhat, it doesn't do that:
% gdb a.out
(gdb) p &t
$1 = (double *) 0x601038 <t>
(gdb) r
Starting program: /home/phan/a.out
[Inferior 1 (process 23337) exited normally]
(gdb) p &t
$2 = (double *) 0x601038 <t>
BTW, this only occurs in Ubuntu 18.04. In Ubuntu 16.04, it works exactly as Redhat, for example the address is the same before and after.
You are presumably seeing pre and post-relocation addresses for the .bss segment.
You can avoid this by disabling position independent executables, thus making gcc choose the final address of the .bss register up front:
gcc -no-pie foo.c
-static would have the effect.
I don't know why there'd be a difference between Ubuntu and Redhat though.
I was trying to learn how to use rbp/ebp to visit function parameters and local variables on ubuntu1604, 64bit. I've got a simply c file:
#include<stdio.h>
int main(int argc,char*argv[])
{
printf("hello\n");
return argc;
}
I compiled it with:
gcc -g my.c
Then debug it with argument parameters:
gdb --args my 01 02
Here I know the "argc" should be 3, so I tried to check:
(gdb) b main
Breakpoint 1 at 0x400535: file ret.c, line 5.
(gdb) r
Starting program: /home/a/cpp/my 01 02
Breakpoint 1, main (argc=3, argv=0x7fffffffde98) at ret.c:5
5 printf("hello\n");
(gdb) x $rbp+4
0x7fffffffddb4: 0x00000000
(gdb) x $rbp+8
0x7fffffffddb8: 0xf7a2e830
(gdb) x/1xw $rbp+8
0x7fffffffddb8: 0xf7a2e830
(gdb) x/1xw $rbp+4
0x7fffffffddb4: 0x00000000
(gdb) x/1xw $rbp
0x7fffffffddb0: 0x00400550
I don't find any clue that a dword of "3" is saved in any of bytes in $rbp+xBytes. Did I get anything wrong in my understanding or commands?
Thanks!
I was trying to learn how to use rbp/ebp to visit function parameters and local variables
The x86_64 ABI does not use stack to pass parameters; they are passed in registers. Because of that, you wouldn't find them at any offset off $rbp (this is different from ix86 calling convention).
To find the parameters, you'll need to look at the $rdi and $rsi regusters:
Breakpoint 1, main (argc=3, argv=0x7fffffffe3a8) at my.c:4
4 printf("hello\n");
(gdb) p/x $rdi
$1 = 0x3 # matches argc
(gdb) p/x $rsi
$2 = 0x7fffffffe3a8 # matches argv
x $rbp+4
You almost certainly wouldn't find anything useful at $rbp+4, because it is usually incremented or decremented by 8, in order to store the entire 64-bit value.
I am trying to hook sys_execve syscall in Linux kernel v3.5 on x86_32. I simply change sys_call_table entry address to my hook function
asmlinkage long (*real_execve)( const char __user*, const char __user* const __user*,
const char __user* const __user* );
...
asmlinkage long hook_execve( const char __user* filename, const char __user* const __user* argv,
const char __user* const __user* envp )
{
printk( "Called execve hook\n" );
return real_execve( filename, argv, envp );
}
...
real_execve = (void*)sys_call_table[ __NR_execve ];
sys_call_table[ __NR_execve ] = (unsigned long)hook_execve;
I do set page permission for modifying sys_call_table entries, and mentioned scheme works well for another syscalls (chdir, mkdir and so on). But on execve hooking i got null pointer dereference:
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596033] Called execve hook
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596408] BUG: unable to handle kernel NULL pointer dereference at (null)
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596486] IP: [< (null)>] (null)
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596526] *pdpt = 0000000032302001 *pde = 0000000000000000
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596584] Oops: 0010 [#1] SMP
I call sys_execve with three parameters because of arch/x86/kernel/entry_32.S, that contains PTREGSCALL3(execve). However, i've tried calling it with four parameters (adding struct pt_regs*) but i got the same error. Maybe something is totally wrong with this approach to execve? Or did i miss something?
UPDATE #1
I found that sys_call_table[ __NR_execve ] actually contains address of ptregs_execve (not sys_execve). It is defined as follows in arch/x86/kernel/entry_32.S:
#define PTREGSCALL3(name) \
ENTRY(ptregs_##name) ; \
CFI_STARTPROC; \
leal 4(%esp),%eax; \
pushl_cfi %eax; \
movl PT_EDX(%eax),%ecx; \
movl PT_ECX(%eax),%edx; \
movl PT_EBX(%eax),%eax; \
call sys_##name; \
addl $4,%esp; \
CFI_ADJUST_CFA_OFFSET -4; \
ret; \
CFI_ENDPROC; \
ENDPROC(ptregs_##name)
...
PTREGSCALL3(execve)
So in order to modify sys_execve i need to replace its code without modifying its address? I have read something similar here, is this the way to go?
UPDATE #2
Actually i found following call sequence: do_execve->do_execve_common->search_binary_handler->security_bprm_check, and this security_bprm_check is a wrapper around LSM(Linux Security Module) operation, that controls execution of a binary. After that i've read and followed this link and i got it working. It solves my problem as now i can see the name of process to be executed, but i am still unsure about correctness of it. Maybe someone else will add some clarity about all this stuff.
In the past, hooking syscalls in the Linux kernel was an easier task, however, in newer kernels, assembly stubs were added to the syscalls. In order to solve this problem, I patch the kernel's memory on the fly.
You can view my full solution for hooking sys_execve here:
https://github.com/kfiros/execmon
Here is my codes:
#include <stdio.h>
int main()
{
fopen("./1.txt","r");
printf("hello");
return 0;
}
$g++ -g -o m main.cpp
$gdb ./m
(gdb) b fopen
Breakpoint 1 at 0x804842c
(gdb) b printf
Breakpoint 2 at 0x804843c
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804842c <fopen#plt>
2 breakpoint keep y 0x0804843c <printf#plt>
(gdb) r
it seems that the breakpoint at function fopen never work ,but at printf works fine.
why?
Thanks
It's a bug in GDB, which appears to be fixed in current CVS sources (as of 20120124).
The problem is that there are two versions of fopen in 32-bit libc.so.6 on Linux, and GDB used to select the wrong one:
nm -D /lib32/libc.so.6 | grep '\<fopen\>'
0005d0c0 T fopen
00109750 T fopen
readelf -s /lib32/libc.so.6 | egrep '0005d0c0|00109750'
181: 0005d0c0 50 FUNC GLOBAL DEFAULT 12 fopen##GLIBC_2.1
182: 00109750 136 FUNC GLOBAL DEFAULT 12 fopen#GLIBC_2.0
679: 0005d0c0 50 FUNC GLOBAL DEFAULT 12 _IO_fopen##GLIBC_2.1
680: 00109750 136 FUNC GLOBAL DEFAULT 12 _IO_fopen#GLIBC_2.0
If you also break on main, and repeat info break, you'll see that GDB set the breakpoint on fopen#GLIBC_2.0, but the function that is called is the fopen##GLIBC_2.1.