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
相关推荐
Chengbei119 小时前
DSH渗透测试插件dsh-pentest全新升级!适配DeepSeek Harness,可视化探索链路,一键搭建轻量化AI渗透测试环境。
人工智能·web安全·网络安全·微信·小程序·系统安全·安全架构
深念Y14 小时前
从 Windows 迁移到 Linux 开发环境的记录
linux·windows·链接·bun·ram·imdisk
Latticy16 小时前
vulnhub系列靶机-mrRobot
web安全·网络安全·渗透测试
Cerman20 小时前
QEMU启动OVMF shell超时分析
c语言·windows·经验分享
白猫不黑20 小时前
网络安全/信息安全专业学习路线与入行指南:从大学到岗位的完整规划
网络·学习·安全·web安全·网络安全·黑客技术
xierui12312320 小时前
AI Agent 隐私架构:本地化重点为什么是登录态与执行权限
java·人工智能·网络安全·架构
Chockmans1 天前
春秋云境CVE-2025-49113
安全·web安全·网络安全·网络攻击模型·安全威胁分析·春秋云境·cve-2025-49113
白猫不黑1 天前
从运维到网络安全:转行优势、路径与薪资前景全解析
运维·网络·web安全·网络安全·信息安全·渗透测试
AI备忘录1 天前
(十一)DHCP 配置命令五厂商对照:华为 华三 锐捷 迈普 思科
服务器·网络·网络协议·网络安全·华为
0xBADCODE1 天前
Flask SSTI读SECRET_KEY+伪造Session:税务系统渗透全流程
前端·后端·python·安全·web安全·网络安全·flask