Return 从 Shellcode 而不是退出
Return from Shellcode instead of exit
我正在为 uni 进行共享内存分配,我有 'borrowed' 和 'massaged' 一些我在 post 中看到的 shellcode 我在这里读过并且其他地方。我已经能够构建一个在我的 MacBook (Mojave) 上运行的示例,并且几乎可以满足我的要求。
但是,由于我在 OS 环境(本例中为 MacOS)中的汇编编程经验不多,而且我不完全理解下面的汇编,所以我需要一点帮助来解决我的最后一个问题。
在我的 C 样板包装器中,我有一个周期性调用我的 shellcode 的循环,但该循环只执行一次迭代。这使我得出结论,第二个 syscall
(在下面的代码中)正在执行 exit 0
,从而终止该过程。
如何将程序集修改为 return 而不是 exit?
注意 如果有人问我,我可以 post 关于我正在使用的包装器代码和工具的更多信息。
bits 64
Section .text
global start
start:
jmp short MESSAGE ;00000000 EB24 jmp short 0x26
GOBACK:
mov eax, 0x2000004 ;00000002 B804000002 mov eax,0x2000004 ; write
mov edi, 0x1 ;00000007 BF01000000 mov edi,0x1
lea rsi, [rel msg] ;0000000C 488D3518000000 lea rsi,[rel 0x2b]
mov edx, 0xf ;00000013 BA0F000000 mov edx,0xf
syscall ;00000018 0F05 syscall
mov eax,0x2000001 ;0000001A B801000002 mov eax,0x2000001 ;exit
mov edi,0x0 ;0000001F BF00000000 mov edi,0x0
syscall ;00000024 0F05 syscall
MESSAGE:
call GOBACK
msg: db "Hello, world!", 0dh, 0ah
.len: equ $ - msg
这是我的 C 样板代码,其中包括上面的 shellcode。
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\xb8\x01\x00\x00\x02\xbf\x00\x00\x00\x00\x0f\x05\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";
int main(int argc, char **argv)
{
void *mem = mmap(0, sizeof(shellcode), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memcpy(mem, shellcode, sizeof(shellcode));
mprotect(mem, sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC);
for (int i = 0; i < 10; i++) {
int (*func)();
func = (int (*)())mem;
(int)(*func)();
sleep(5);
}
munmap(mem, sizeof(shellcode));
return 0;
}
I have a loop that calls my shellcode
因此,如果它是实际的 call
,那么您就可以开始了,唯一需要做的更改是删除最后 3 条指令(mov
、mov
和 syscall
) 并用 ret
替换它们,因为 return 地址已经在堆栈上了。但是我们需要额外清理一下堆栈,因为文本字符串的地址是为了 syscall
而放在那里的,我们想在 return 之前摆脱它。
此外,由于您的 shellcode 包含一个偏移量(第一个 jmp
操作码的值为 0x24
),因此不删除任何内容(因为它会更改偏移量)更安全,而是用 NOP
。除非你每次都修改 shellcode 的源代码并生成它——否则删除东西就没问题了。
所以我实际上建议做的是用 0x90
(NOP) 替换构成最后 3 个操作码的字节,最后 2 个字节替换为 pop rax\ret
所以字节0x58
和 0xc3
。最终的 shellcode 可能如下所示:
const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x58\xc3\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";
我正在为 uni 进行共享内存分配,我有 'borrowed' 和 'massaged' 一些我在 post 中看到的 shellcode 我在这里读过并且其他地方。我已经能够构建一个在我的 MacBook (Mojave) 上运行的示例,并且几乎可以满足我的要求。
但是,由于我在 OS 环境(本例中为 MacOS)中的汇编编程经验不多,而且我不完全理解下面的汇编,所以我需要一点帮助来解决我的最后一个问题。
在我的 C 样板包装器中,我有一个周期性调用我的 shellcode 的循环,但该循环只执行一次迭代。这使我得出结论,第二个 syscall
(在下面的代码中)正在执行 exit 0
,从而终止该过程。
如何将程序集修改为 return 而不是 exit?
注意 如果有人问我,我可以 post 关于我正在使用的包装器代码和工具的更多信息。
bits 64
Section .text
global start
start:
jmp short MESSAGE ;00000000 EB24 jmp short 0x26
GOBACK:
mov eax, 0x2000004 ;00000002 B804000002 mov eax,0x2000004 ; write
mov edi, 0x1 ;00000007 BF01000000 mov edi,0x1
lea rsi, [rel msg] ;0000000C 488D3518000000 lea rsi,[rel 0x2b]
mov edx, 0xf ;00000013 BA0F000000 mov edx,0xf
syscall ;00000018 0F05 syscall
mov eax,0x2000001 ;0000001A B801000002 mov eax,0x2000001 ;exit
mov edi,0x0 ;0000001F BF00000000 mov edi,0x0
syscall ;00000024 0F05 syscall
MESSAGE:
call GOBACK
msg: db "Hello, world!", 0dh, 0ah
.len: equ $ - msg
这是我的 C 样板代码,其中包括上面的 shellcode。
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\xb8\x01\x00\x00\x02\xbf\x00\x00\x00\x00\x0f\x05\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";
int main(int argc, char **argv)
{
void *mem = mmap(0, sizeof(shellcode), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memcpy(mem, shellcode, sizeof(shellcode));
mprotect(mem, sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC);
for (int i = 0; i < 10; i++) {
int (*func)();
func = (int (*)())mem;
(int)(*func)();
sleep(5);
}
munmap(mem, sizeof(shellcode));
return 0;
}
I have a loop that calls my shellcode
因此,如果它是实际的 call
,那么您就可以开始了,唯一需要做的更改是删除最后 3 条指令(mov
、mov
和 syscall
) 并用 ret
替换它们,因为 return 地址已经在堆栈上了。但是我们需要额外清理一下堆栈,因为文本字符串的地址是为了 syscall
而放在那里的,我们想在 return 之前摆脱它。
此外,由于您的 shellcode 包含一个偏移量(第一个 jmp
操作码的值为 0x24
),因此不删除任何内容(因为它会更改偏移量)更安全,而是用 NOP
。除非你每次都修改 shellcode 的源代码并生成它——否则删除东西就没问题了。
所以我实际上建议做的是用 0x90
(NOP) 替换构成最后 3 个操作码的字节,最后 2 个字节替换为 pop rax\ret
所以字节0x58
和 0xc3
。最终的 shellcode 可能如下所示:
const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x58\xc3\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";