WIndows ShellCode开发 第四章 动态API调用

文章目录

    • [WIndows ShellCode开发 第四章 动态API调用](#WIndows ShellCode开发 第四章 动态API调用)

WIndows ShellCode开发 第四章 动态API调用

不检验直接跳到这一章,最好是将第一章命令仔细看完然后再来这一章,因为已经写过一遍的缘故,其中代码可以只会将重要部分进行注释,并且逻辑讲解也会少很多

消息框汇编程序

asm 复制代码
BITS 64
SECTION .text
global main
main:
sub rsp,0x28
and rsp,0xFFFFFFFFFFFFFFF0
xor rcx,rcx
mov rax,[gs:rcx+0x60]	; PEB
mov rax,[rax+0x18]	; PEB->LDR
mov rsi,[rax+0x10]	; PEB->LDR->InLoadOrderModuleList
mov rsi,[rsi]
mov rsi,[rsi]
mov rbx,[rsi+0x30]	; kernel32.dll base
mov r8,rbx	; kernel32.dll base --> r8
mov eax,[rbx+0x3C]     ; 获取 PE Header 的偏移 (e_lfanew)
add rax,r8            ; RAX = PE Header 的实际地址
mov edx,[rax+0x88]     ; 获取导出表 (Export Directory) 的 RVA
add rdx,r8            ; RDX = 导出表的实际内存地址 (Export Directory VA)
mov r10d,[rdx+0x14]	; 函数总数
xor r11,r11	
mov r11d,[rdx+0x20]	; AddressOfNames RVA
add r11,r8
mov rcx,r10	; 计量器的总数
mov rax,0x9090737365726464	; 'ddress'
shl rax,0x10
shr rax,0x10	; 前面两个0x90是占位符,避免ShellCode中出现空字节(0x00)
push rax
mov rax,0x41636F7250746547	; GetProcA 
push rax
mov rax,rsp
kernel32findfunction:
jecxz FunctionNameNotFound	; 计量总数到零跳转到FunctionNameNotFound
xor ebx,ebx
mov ebx,[r11+rcx*4]
add rbx,r8
dec rcx
mov r9,qword[rax]	; qword[rax] 表示读取8字节内容,为"GetProcA"
cmp [rbx],r9	; [rbx]读取与r9相对应的字节数进行匹配
jnz kernel32findfunction	; 第一次粗滤匹配
mov r9d,dword[rax+8]	; 读取rax+8地址(GetProcA后面那几个字节`ddress`)的四字节数据,读取四个字节并进行比较是因为核心字节已经读取到了可以拿来进行匹配,并避免了读取到零字符。
cmp [rbx+8],r9d	; r9d 是32位的,所以[rbx+8]自动读取4字节数据与r9d内进行比较
jz FunctionNameFound
jnz kernel32findfunction
FunctionNameNotFound:
int3
FunctionNameFound:
push rcx
pop r15
inc r15
xor r11,r11
mov r11d,[rdx+0x1c]	; AddressOfFunctions RVA
add r11,r8
mov eax,[r11+r15*4]
add rax,r8
push rax
pop r15
mov r12,r15	; 将GetProcAddress地址存一下后续需要用到r15
mov rdi,r8
mov rcx,r8	; 给 GetProcAddress 准备第一个参数
mov rax,0x41797261	; 构造LoadLibraryA字符串,后4字节(aryA)先压栈
push rax
mov rax,0x7262694C64616F4C	; LoadLibr
push rax
mov rdx,rsp	; 给 GetProcAddress 准备第二个参数
sub rsp,0x30
call r15
add rsp,0x30
mov r15,rax	; GetProcAddress 函数执行完毕后,会将返回值(即目标函数的地址)写入 rax 寄存器,因此此时的RAX的值成为 LoadLibraryA 函数的地址,然后存入r15
mov r14,r12	; 将 GetProcAddress地址 存到r14
mov rcx,rdi	; 将 kernel32.dll 基址作为第一参数,(基地址=DLL句柄)
mov rax,0x90737365	; 0x90作为占用符,避免空字节
shl eax,0x8
shr eax,0x8
push rax
mov rax,0x636F725074697845	; ExitProc
push rax
mov rdx,rsp	; 第二个参数存入`rdx`
sub rsp,0x30
call r14
add rsp,0x30
mov r14,rax	; 将RAX中ExitProcess函数地址传给R14
mov rax, 0x90906C6C	; 构造 "ll" 字符串,前两个字节直接用nop填充
shl eax,0x10
shr eax,0x10
push rax
mov rax, 0x642E323372657375	; 构造 "user32.d" 字符串
push rax
mov rcx,rsp	; 将构造好的字符串传给rcx作为第一参数
sub rsp,0x30
call r15	; 调用LoadLibraryA 加载 user32.dll
mov rdi,rax	; 将user32.dll基地址保存到rdi
mov rcx,rdi
mov rax,0x9041786F	; "oxA"字符串
shl eax,0x8
shr eax,0x8
push rax
mov rax,0x426567617373654D	; 'MessageB'字符串
push rax
mov rdx,rsp	; 将MessageBoxA作为第二参数
sub rsp,0x30
call r12	; 调用GetProcAddress
mov r15,rax	; 将 MessageBoxA 函数地址传入r15
xor rcx,rcx
mov rax,0x90909073
shl eax,24
shr eax,24
push rax
mov rax,0x6B6E616C62656E6F
push rax
mov rdx,rsp	; 第二参数,lpText
mov r8,rsp	; 第三参数,lpCaption
xor r9d,r9d
sub rsp,0x30
call r15
add rsp, 0x30
xor ecx,ecx
call r14

直接编译链接

复制代码
nasm -f win64 mesg.asm -o mesg.obj
gcc -m64 mesg.obj -o mesg.exe -lkernel32 -nostartfiles 

双击mesg.exe,成功弹窗

接下来将这些编译为ShellCode在加载器执行

复制代码
nasm.exe -f win64 mesg.asm -o mesg.o

$shellcode = ""; (objdump -D mesg.o | Select-String "^ ").Line | ForEach-Object { $_.Split("`t")[1] -split " " | Where-Object { $_ -match "^[0-9a-f]{2}$" } | ForEach-Object { $shellcode += "\x" + $_ } }; $shellcode

简单加载器C语言

复制代码
#include <windows.h>
#include <stdio.h>
#include <signal.h>

unsigned char shellcode[] = 
"\x48\x83\xec\x28\x48\x83\xe4\xf0\x48\x31\xc9\x65\x48\x8b\x41\x60\x48\x8b\x40\x18\x48\x8b\x70\x10\x48\x8b\x36\x48\x8b\x36\x48\x8b\x5e\x30\x49\x89\xd8\x8b\x43\x3c\x4c\x01\xc0\x8b\x90\x88\x00\x00\x00\x4c\x01\xc2\x44\x8b\x52\x14\x4d\x31\xdb\x44\x8b\x5a\x20\x4d\x01\xc3\x4c\x89\xd1\x48\xb8\x64\x64\x72\x65\x73\x73\x90\x90\x48\xc1\xe0\x10\x48\xc1\xe8\x10\x50\x48\xb8\x47\x65\x74\x50\x72\x6f\x63\x41\x50\x48\x89\xe0\x67\xe3\x20\x31\xdb\x41\x8b\x1c\x8b\x4c\x01\xc3\x48\xff\xc9\x4c\x8b\x08\x4c\x39\x0b\x75\xe9\x44\x8b\x48\x08\x44\x39\x4b\x08\x74\x03\x75\xdd\xcc\x51\x41\x5f\x49\xff\xc7\x4d\x31\xdb\x44\x8b\x5a\x1c\x4d\x01\xc3\x43\x8b\x04\xbb\x4c\x01\xc0\x50\x41\x5f\x4d\x89\xfc\x4c\x89\xc7\x4c\x89\xc1\xb8\x61\x72\x79\x41\x50\x48\xb8\x4c\x6f\x61\x64\x4c\x69\x62\x72\x50\x48\x89\xe2\x48\x83\xec\x30\x41\xff\xd7\x48\x83\xc4\x30\x49\x89\xc7\x4d\x89\xe6\x48\x89\xf9\xb8\x65\x73\x73\x90\xc1\xe0\x08\xc1\xe8\x08\x50\x48\xb8\x45\x78\x69\x74\x50\x72\x6f\x63\x50\x48\x89\xe2\x48\x83\xec\x30\x41\xff\xd6\x48\x83\xc4\x30\x49\x89\xc6\xb8\x6c\x6c\x90\x90\xc1\xe0\x10\xc1\xe8\x10\x50\x48\xb8\x75\x73\x65\x72\x33\x32\x2e\x64\x50\x48\x89\xe1\x48\x83\xec\x30\x41\xff\xd7\x48\x89\xc7\x48\x89\xf9\xb8\x6f\x78\x41\x90\xc1\xe0\x08\xc1\xe8\x08\x50\x48\xb8\x4d\x65\x73\x73\x61\x67\x65\x42\x50\x48\x89\xe2\x48\x83\xec\x30\x41\xff\xd4\x49\x89\xc7\x48\x31\xc9\xb8\x73\x90\x90\x90\xc1\xe0\x18\xc1\xe8\x18\x50\x48\xb8\x6f\x6e\x65\x62\x6c\x61\x6e\x6b\x50\x48\x89\xe2\x49\x89\xe0\x45\x31\xc9\x48\x83\xec\x30\x41\xff\xd7\x48\x83\xc4\x30\x31\xc9\x41\xff\xd6";

// 异常处理函数
void handler(int sig) {
    printf("Exception occurred! (signal %d)\n", sig);
    exit(1);
}

int main() {
    printf("Loading Shellcode...\n");
    printf("Shellcode size: %d bytes\n", sizeof(shellcode));
    
    // 注册异常处理
    signal(SIGSEGV, handler);
    signal(SIGILL, handler);
    
    // 申请可执行内存
    void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (exec == NULL) {
        printf("VirtualAlloc failed: %d\n", GetLastError());
        return 1;
    }
    
    memcpy(exec, shellcode, sizeof(shellcode));
    printf("Shellcode at: 0x%p\n", exec);
    printf("Press ENTER to execute...");
    getchar();
    
    printf("Executing...\n");
    
    // 执行shellcode
    ((void(*)())exec)();
    
    printf("Shellcode returned (should not happen)\n");
    VirtualFree(exec, 0, MEM_RELEASE);
    return 0;
}

gcc -o loader.exe loader.c -m64
相关推荐
一个人旅程~15 分钟前
电脑里要装三系统win7/win11/linux,按照什么顺序和格式安装才不会导致启动表出问题?
linux·windows·经验分享·电脑
xiaoshuaishuai815 分钟前
C# 克隆Git仓库
服务器·windows·c#
菩提小狗10 小时前
每日安全情报报告 · 2026-04-20
网络安全·漏洞·cve·安全情报·每日安全
liuyukuan11 小时前
如何在win11上打开 WSL2(Windows 的 Linux 子系统)?
linux·windows
云安全助手11 小时前
2026年AI安全大模型实战指南:快快云安全AI能力全景解析
人工智能·网络安全·claude
寺中人11 小时前
Windows系统的动态磁盘卷
windows·系统·教程
忧郁的蛋~12 小时前
基于.NET的Windows窗体编程之WinForms数据表格
windows·.net
zmj32032415 小时前
欧盟 R155 核心范围
网络安全·信息安全
鼹鼠SDN15 小时前
手机访问家里局域网共享文件?MoleSDN 叶子路由一步融入家庭内网
windows·智能手机·远程控制
Han.miracle15 小时前
Redis 全套笔记:基础 API + 三大架构 + 缓存三大问题
java·windows·redis