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
相关推荐
idolao2 小时前
RStudio 2025 + R 4.5.0 安装与配置教程 Windows版:解压+双软件安装+自定义路径+R语言关联指南
windows
Leo655353 小时前
动态透视报表 + 查询接口 + Excel导出
开发语言·windows·python
vortex55 小时前
HackMyVM: Flute 靶机渗透题解
网络安全
一名优秀的码农6 小时前
vulhub系列-48-Hack_Me_Please(超详细)
安全·web安全·网络安全·网络攻击模型·安全威胁分析
vortex56 小时前
vmware虚拟机设置启动时进入live cd
linux·网络安全
One_Blanks6 小时前
WIndows x64 ShellCode开发 第五章 反向Shell编写
windows·网络安全·渗透测试
一只鼠标猴6 小时前
甲方应急响应:从事件处置到溯源闭环实战指南
安全·web安全·网络安全·应急响应·应急·应急溯源
玖釉-7 小时前
暴力美学与极致性能:深度解析 Meshoptimizer 的 Sloppy 减面算法
c++·windows·图形渲染
dashizhi20157 小时前
服务器共享文件禁止下载、禁止拖动共享文件到本地磁盘、禁止拷贝共享文件
运维·服务器·windows