I need help running a program in an executable using GDB.
I have an executable file name vuln. I do not know the source code as I am doing a CTF. When I analyzed the executable, I found three exciting functions: main, vuln, and flag. Vuln func is vulnerable to BOF attack, but I do not want to go that way. What I am trying to do is run the executable in gdb, and I used print (void) flag(param1, param2) command to directly run flag func as this is supposed to give me a flag; however, it does not work as it says my parameters are incorrect which I am sure are not. I have also found out about the jump function, but I cannot pass any parameters.
So is there any way to run a function from executable with parameters properly or I would have to go through the pain of BOF.
GHIDRA disassembled code of FLAG and VULN Func are below.
void flag(int param_1, int param_2){
char local_50 [64];
FILE *local_10;
local_10 = fopen("flag.txt", "r");
if(local_10 != (FILE *)0x0){
fgets(local_50, 0x40, local_10);
if ((param_1 == -0x21524111) && (param_2 == -0x3f212ff3)){
printf(local_50);
}
return;
}
puts("Hurry up and try in on server side.");
exit(0);
}
void vuln(void)
{
char local_bc [180];
gets(local_bc);
puts(local_bc);
return;
}
print (void) flag(param1, param2)
Not sure what your values of param1 and param2 are, but this seems to work just fine for me:
echo "hello" > flag.txt
gdb -q ./a.out
(gdb) start
Temporary breakpoint 4 at 0x555555555307
Starting program: /tmp/a.out
Thread 1 "a.out" hit Temporary breakpoint 4, 0x0000555555555307 in main ()
(gdb) p (void)flag(-0x21524111, -0x3f212ff3)
hello
$2 = void
(gdb)
I am debugging something and would like to use typeid in the typeinfo header file. I am coming from a beginner Python background using pdb where you could import a library and test things while in the session.
Is it possible to include extra header files in a running gdb session [specifically those in the std library] or is including the headers [say typeinfo] before compilation the only way?
typeid is not a header file, it is an operator, referring to an object of the polymorphic type const std::type_info or of some type derived from it. See documentation.
You can call it during debug session and see it's return value without any additional steps like importing a library. See example debug session for a test program:
#include <iostream>
int main() {
int a = 1;
double b = 2;
std::cout << a << std::endl;
std::cout << b << std::endl;
return 0;
}
$ gdb -q ./a.out
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x40118e: file t1.cpp, line 4.
Temporary breakpoint 1, main () at t1.cpp:4
4 int a = 1;
(gdb) n
5 double b = 2;
(gdb)
7 std::cout << a << std::endl;
(gdb) p typeid(a)
$1 = {_vptr.type_info = 0x7ffff7f81340 <vtable for __cxxabiv1::__fundamental_type_info+16>, __name = 0x7ffff7f2f654 <typeinfo name for int> "i"}
(gdb) p typeid(b)
$2 = {_vptr.type_info = 0x7ffff7f81340 <vtable for __cxxabiv1::__fundamental_type_info+16>, __name = 0x7ffff7f2f693 <typeinfo name for double> "d"}
I'm using gdb for debugging a program. And what I see is kind of strange:
(gdb) bt
0xb59656f8 in globalCallStubClass::addCallContext (**this=0x0**)
at /ccase_enodeb/callp/build_callp/src/test/framework/shared/src/shared_call_context.cc:1962
0xb5b52e64 in rrcStubClass::process_scenario_spontaneous_trigger_RRC_CONNECTION_REQUEST (gcppMsgCtx=...)
at /ccase_enodeb/callp/build_callp/src/test/framework/rrc/src/rrc_connection_request.cc:90
0xb6c3be4c in Gcpp::routeMessage (this=0xb392e9d0) at /ccase_enodeb/callp/build_callp/src/callp_services/gcpp/src/gcpp.cc:1095
0xb6c3b3b0 in Gcpp::loop (this=0xb392e9d0, Default_Method_Ptr=0)
at /ccase_enodeb/callp/build_callp/src/callp_services/gcpp/src/gcpp.cc:925
0xb58d2ae0 in stubBthdEntryPoint () at /ccase_enodeb/callp/build_callp/src/test/framework/root/src/stub_root.cc:314
0x000191f8 in lxb_thd_entry (pCtx=0x68c0f8) at /vobs/onepltf/ltefdd/core/src/lxbase/lxbase.c:3289
0xb575602e in start_thread () from /lib/arm-linux-gnueabi/libpthread.so.0
0xb56d6ab8 in ?? () from /lib/arm-linux-gnueabi/libc.so.6
0xb56d6ab8 in ?? () from /lib/arm-linux-gnueabi/libc.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) print pCallStub
$1 = (globalCallStubClass *) **0x7a1da8**
(gdb) print this
$2 = (globalCallStubClass * const) **0x0**
The chrash appears at line marked with (-->):
if (pCallStub != NULL) {
-->callStubClass* pCallInst = pCallStub->addCallContext();
}
Function addCallContext is called for object pCallStub (pCallStub is instantiated and is not NULL). When I print pCallStub I can see that it has an address:
(gdb) print pCallStub
$1 = (globalCallStubClass *) 0x7a1da8
but still, this (which should be pCallStub) is 0x0:
(gdb) print this
$2 = (globalCallStubClass * const) 0x0
Can anyone help me?
Thanks,
Geta
pCallStub is 0x0, so it's pointing to NULL. You have to instantiate an object with pCallStub = new globalCallStubClass() or a creator function like pCallStub = createGlobalCallStubClass() before using the pointer.
(gdb) print pCallStub
$1 = (globalCallStubClass *) **0x7a1da8**
(gdb) print this
$2 = (globalCallStubClass * const) **0x0**
You need to show more code for us to understand your issue.
There is no context here where we could see where this == pCallStub
Also, if you have optimizations turned on, you might not see what you think you're seeing (like the compiler optimized the function call and the stack so gdb doesn't report the right variable because it search it on the stack. Typically, on a x86 system, you'll find "this" in ecx register.
Since you have multiple thread you can have the "multithread singleton issue", that is, one thread is allocating and storing in the singleton instance, but other thread don't see it yet.
Try to use atomic compare and swap to set the singleton instance for example.
Is there a way to define a new data type (C structure or union) in gdb. The idea is to define a structure and then make gdb print data from an address interpreted as the newly defined structure.
For example, lets say we have a sample structure.
struct sample {
int i;
struct sample *less;
struct sample *more;
}
And if 0x804b320 is the address of an array of struct sample. The binary doesn't have debugging information so that gdb understands struct sample. Is there any way to define struct sample in a gdb session? So that we can print p *(struct sample *)0x804b320
Yes, here is how to make this work:
// sample.h
struct sample {
int i;
struct sample *less;
struct sample *more;
};
// main.c
#include <stdio.h>
#include <assert.h>
#include "sample.h"
int main()
{
struct sample sm;
sm.i = 42;
sm.less = sm.more = &sm;
printf("&sm = %p\n", &sm);
assert(sm.i == 0); // will fail
}
gcc main.c # Note: no '-g' flag
gdb -q ./a.out
(gdb) run
&sm = 0x7fffffffd6b0
a.out: main.c:11: main: Assertion `sm.i == 0' failed.
Program received signal SIGABRT, Aborted.
0x00007ffff7a8da75 in raise ()
(gdb) fr 3
#3 0x00000000004005cc in main ()
No local variables, no type struct sample:
(gdb) p sm
No symbol "sm" in current context.
(gdb) p (struct sample *)0x7fffffffd6b0
No struct type named sample.
So we get to work:
// sample.c
#include "sample.h"
struct sample foo;
gcc -g -c sample.c
(gdb) add-symbol-file sample.o 0
add symbol table from file "sample.o" at
.text_addr = 0x0
(gdb) p (struct sample *)0x7fffffffd6b0
$1 = (struct sample *) 0x7fffffffd6b0
(gdb) p *$1
$2 = {i = 42, less = 0x7fffffffd6b0, more = 0x7fffffffd6b0}
VoilĂ !
I'm using the driver I posted at Direct Memory Access in Linux to mmap some physical ram into a userspace address. However, I can't use GDB to look at any of the address; i.e., x 0x12345678 (where 0x12345678 is the return value of mmap) fails with an error "Cannot access memory at address 0x12345678".
Is there any way to tell GDB that this memory can be viewed? Alternatively, is there something different I can do in the mmap (either the call or the implementation of foo_mmap there) that will allow it to access this memory?
Note that I'm not asking about /dev/mem (as in the first snippet there) but about a mmap to memory acquired via ioremap(), virt_to_phys() and remap_pfn_range()
I believe Linux does not make I/O memory accessible via ptrace(). You could write a function that simply reads the mmap'ed address and have gdb invoke it. Here's a slightly modified version of your foo-user.c program along with the output from a gdb session.
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
char *mptr;
char peek(int offset)
{
return mptr[offset];
}
int main(void)
{
int fd;
fd = open("/dev/foo", O_RDWR | O_SYNC);
if (fd == -1) {
printf("open error...\n");
return 1;
}
mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 4096);
printf("On start, mptr points to 0x%lX.\n", (unsigned long) mptr);
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
mptr[0] = 'a';
mptr[1] = 'b';
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
close(fd);
return 0;
}
$ make foo-user CFLAGS=-g
$ gdb -q foo-user
(gdb) break 27
Breakpoint 1 at 0x804855f: file foo-user.c, line 27.
(gdb) run
Starting program: /home/me/foo/foo-user
On start, mptr points to 0xB7E1E000.
mptr points to 0xB7E1E000. *mptr = 0x61
Breakpoint 1, main () at foo-user.c:27
27 mptr[0] = 'a';
(gdb) n
28 mptr[1] = 'b';
(gdb) print peek(0)
$1 = 97 'a'
(gdb) print peek(1)
$2 = 98 'b'
I have the answer to your conundrum :) I've searched everywhere online without much help and finally debugged it myself.
This post was a good starting point for me. I wanted to achieve something in similar lines, I had implemented a char driver with MMAP to map my custom managed memory to a userspace process. When using GDB, ptrace PEEK calls access_process_vm() to access any memory in your VMA. This causes a EIO error since the generic access cannot get the PA of your memory. It turns out, you have to implement an access function for this memory by implementing .access of your VMA's vm_operations_struct. Below is an example:
//Below code needs to be implemented by your driver:
static struct vm_operations_struct custom_vm_ops = {
.access = custom_vma_access,
};
static inline int custom_vma_access(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
return custom_generic_access_phys(vma, addr, buf, len, write);
}
static int custom_generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
void __iomem *maddr;
//int offset = (addr & (PAGE_SIZE-1)) - vma->vm_start;
int offset = (addr) - vma->vm_start;
maddr = phys_to_virt(__pa(custom_mem_VA));
if (write)
memcpy_toio(maddr + offset, buf, len);
else
memcpy_fromio(buf, maddr + offset, len);
return len;
}
To access the mmapped memory, GDB will call ptrace, which will then call __access_remote_vm() to access the mmapped memory. If the memory is mapped with flags such as VMIO | VM_PFNMAP (for example, remap_pfn_range() sets them), GDB will access the memory though vm's access method defined by users.
Instead of writing our own implementation for access(), kernel already provides a generic version called generic_access_phys(), and this method could be easily linked via vm_operations_struct as the /dev/mem device did:
static const struct vm_operations_struct mmap_mem_ops = {
.access = generic_access_phys };
int mmap_mem()
{
.... ....
vma->vm_ops = &mmap_mem_ops;
.... ....
}
It is my understanding that GDB will be using ptrace to poke around in your process's memory. Perhaps you should write a simple program that just attaches to your process and uses ptrace to read from that memory. This might help narrow down what the underlying problem is. If that has no issues, then you know either I'm wrong :), or something else fishy is happening with GDB.
you go "info files"
(gdb) help info files
Names of targets and files being debugged.
Shows the entire stack of targets currently in use (including the exec-file,
core-file, and process, if any), as well as the symbol file name.
(gdb) info files
Symbols from "/bin/ls".
Unix child process:
Using the running image of child Thread 4160418656 (LWP 10729).
While running this, GDB does not access memory from...
Local exec file:
`/bin/ls', file type elf32-powerpc.
Entry point: 0x10002a10
0x10000134 - 0x10000141 is .interp
0x10000144 - 0x10000164 is .note.ABI-tag
0x10000164 - 0x100008f8 is .gnu.hash
0x100008f8 - 0x10001728 is .dynsym
0x10001728 - 0x100021f3 is .dynstr
0x100021f4 - 0x100023ba is .gnu.version
...
0x0ffa8300 - 0x0ffad8c0 is .text in /lib/libacl.so.1
0x0ffad8c0 - 0x0ffad8f8 is .fini in /lib/libacl.so.1
0x0ffad8f8 - 0x0ffadbac is .rodata in /lib/libacl.so.1
0x0ffadbac - 0x0ffadd58 is .eh_frame_hdr in /lib/libacl.so.1
0x0ffadd58 - 0x0ffae4d8 is .eh_frame in /lib/libacl.so.1
0x0ffbe4d8 - 0x0ffbe4e0 is .ctors in /lib/libacl.so.1
0x0ffbe4e0 - 0x0ffbe4e8 is .dtors in /lib/libacl.so.1
...
(gdb) info sh
From To Syms Read Shared Object Library
0xf7fcf960 0xf7fe81a0 Yes /lib/ld.so.1
0x0ffd0820 0x0ffd5d10 Yes /lib/librt.so.1
0x0ffa8300 0x0ffad8c0 Yes /lib/libacl.so.1
0x0ff6a840 0x0ff7f4f0 Yes /lib/libselinux.so.1
0x0fdfe920 0x0ff1ae70 Yes /lib/libc.so.6
0x0fda23d0 0x0fdb0db0 Yes /lib/libpthread.so.0
Failing this, you can use "mem" to configure memory ranges.
(gdb) mem 1 1414
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 y 0x00000001 0x00000586 rw nocache
(gdb) disable mem 1
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 n 0x00000001 0x00000586 rw nocache
I think that if that memory is not accessible by GDB then it is not mapped into your process address space and so you get "Cannot access memory at addresss 0x12345678". If that application were run normally you would get a segmentation fault. Also, maybe your driver is screwed and you should check you actually can access the memory from within the kernel. Try with example here:
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
int fd = open("/dev/zero", O_RDONLY);
void* addr = mmap(NULL, 1024, PROT_READ, MAP_PRIVATE, fd, 0);
for (int x = 0; x < 10; x++) {
printf("%X\n", ((char*)addr)[x]);
}
close(fd);
return 0;
}
If you open an AF_PACKET socket and mmap it, gdb can't access this memory. So there isn't a problem with your driver. It's either a problem with ptrace or with gdb.