VS 编译 x64 ASM 下配置 (x86 不需要)
-
Command line : ml64 /Fo $(IntDir)%(fileName).obj /c %(fileName).asm
-
Output : $(IntDir)%(fileName).obj
函数描述
MessageBoxA
user32 下的信息框函数 , 四个参数分别为 :
HWND hWnd, // 窗口句柄
LPCSTR lpText, // 标题
LPCSTR lpCaption, // 内容
UINT uType //按钮类型, 如果为0的话,函数返回值固定为1
printf
C语言标准库函数,是指格式化输出函数
参数1: 格式化的字符串
参数2: 替换的变量
eg: printf ("hello %s"","world"); // 控制台输出 hello world
代码实现
char* title = "this is title"; // 通用 msgbox 标题
char* val = "this is val"; // 通用 msgbox 内容
// 调用 msgbox 会返回eax值,这里在继续调用 printf 函数输出返回值
char* asm_print_format = "asm_ret_resut : %p\n";
// 获取msgbox 函数地址
DWORD_PTR lpAddr = (DWORD_PTR)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
// LOG_INFO 是我自己封装的控制台输出,这里我就注释掉了, 自行打印吧
// LOG_INFO("user32.dll:MessageBoxA addr is -> %p", lpAddr);
// LOG_INFO("printf addr is -> %p", &printf);
// printf("fuckyou %p",0x123); // 这里自己掉用了下 printf 函数, 方便下断观察参数调试
#if defined(_M_X64)
// x64 需要单独创建 asm 文件(如下)来支持内联汇编
asm_msg_box_x64(title, val, lpAddr, asm_print_format);
#else
// x86 asm
__asm {
// 第一个 call调用 msgbox
push 0;
push title;
push val;
push 0;
call lpAddr;
// 第二个call,这里eax 为 msgbox 返回值
push eax;
push asm_print_format;
call printf;
// 堆栈平衡, add esp 4*n, n为参数数量
add esp, 0x8;
}
#endif
_msg_box.asm (x64)
extrn printf: proc ;
extrn MessageBoxA: proc ;
.data
.CODE ;
asm_msg_box_x64 PROC ;
push rbp
sub rsp,30h ; // 这里的 30h与 add rsp 对应, 进⼊call之前rsp必须要满⾜0x10 (16)字节对齐,可自行加减8调节 eg(38h)
mov qword ptr [rsp+20h],r9
mov qword ptr [rsp+18h],r8
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
mov r9,0
mov r8, [rsp+8]
mov rdx, [rsp+10h]
mov rcx,0
call qword ptr [rsp+18h] ; // 这里我们是将 msgbox 地址通过变量传递过来了, 也可以在该文件extrn MessageBoxA, 然后直接 call MessageBoxA, 改函数返回值会放到寄存器 rax中
mov rcx,[rsp+20h] ; // x64, 默认前四个参数由 rcx,rdx,r8,r9 四个寄存器传参,printf 俩个参数, 所以用到了 rcx,rdx
mov rdx,rax
// x64 的堆栈平衡全依赖外部的 sub/add esp , 没有call内部的 ret xx 这个约定了
call printf
add rsp,30h ;
pop rbp
ret
asm_msg_box_x64 ENDP ;
END ;
关于堆栈保护
查了一些资料, 要使用内联汇编, 只要不是_declspec(naked)修饰的话 , 编译器会自动为我们写入一些保护指令,
所以这里 不需要在 push rax, push rbx... pop rbx pop rax 来保存恢复堆栈 ,
当然如果是远程注入的话 还是需要保护下的.
x86/x64 远程注入 参考 https://www.52pojie.cn/thread-1504396-1-1.html