VS2019中编写X64汇编

本文介绍在VS2019环境中配置并运行汇编的详细步骤,包括创建空项目、选择生成依赖项、创建asm源文件、修改目标平台、添加程序入口点等,还提及断点调试、查看寄存器值和内存内容的方法,以及解决代码无颜色和智能提示的问题。
本文参考了这位大神的文章,并亲自在vs2019环境中操作了一遍,如有雷同,那就是抄的 。VS2015配置并运行汇编(一步一步照图做)【vs2017的链接在最后】_vs2015汇编环境-优快云博客
创建空项目

建一个空项目,必须先建空项目,改现成的C++项目为assembly项目可能会造成编译不过

选择生成依赖项

创建好了之后,不要着急创建源文件,先对项目进行一些设置。点击菜单栏->项目->生成自定义->选择masn

创建asm源文件

新建一个C++的源文件,将后缀改为.asm

extrn MessageBoxA: proc
 
;64位没有 .model 宏指令,不能指定内存模型和调用约定
 
.data
text db 'Hello World', 0
caption db 'Selph First x64 Application', 0
 
.code
WinMain proc
sub rsp,28h ; 函数调用前需要预留影子空间,对齐rsp
xor r9d,r9d
lea r8, caption
lea rdx, text
xor rcx,rcx
call MessageBoxA ; 函数调用使用fastcall
add rsp,28h
WinMain ENDP
END ; 最后直接end,不用指明符号
重要:把目标平台改为x64

如下,箭头指示的位置,修改一下即可

添加程序入口点

点击菜单栏->项目->属性->连接器->高级->入口点->设置为main

(其实这个可以自己随意设置,写代码的时候,入口函数需要和这里一致)

开始写代码

简单的测试代码,如果能运行就说明环境配置成功了~

断点调试

和VS开发其他语言相同,在代码最左侧可以插入断点,F10单步,F11进入函数内部。

查看寄存器值

因为是没有输出的,所以需要通过调试观察寄存器的值,按F11进入调试,然后点击菜单->调试->窗口->寄存器

查看内存中的内容

菜单->调试->窗口->内存

代码没有颜色,也没有智能提示?

点击菜单->拓展->管理拓展

然后搜索,AsmDude,点击下载,会非常的慢,耐心等待即可,你也可以去微软官网手动下载插件[https://marketplace.visualstudio.com/items?itemName=Henk-JanLebbink.AsmDude]

安装的时候需要把vs关掉,点击end tasks即可

<think>由于用户的问题涉及在Visual Studio 2019中使用x64内联汇编插入特定字节码,但需要注意的是,Visual Studio在x64模式下不支持内联汇编(inline assembly)。因此,我们需要使用其他方法来实现插入特定字节码的目标。 在x64平台上,Visual Studio提供了两种替代方案: 1. 使用独立的汇编文件(.asm),然后通过汇编器(如MASM)进行汇编,再与C++代码链接。 2. 在C++代码中直接嵌入机器码(字节码)数组,然后通过函数指针执行。 用户提到要插入特定字节码,因此我们重点考虑第二种方法。 步骤: 1. 将需要执行的汇编指令转换为机器码(字节码)。 2. 在C++代码中定义一个无符号字符数组(byte数组)来存放这些机器码。 3. 将存放机器码的内存区域设置为可执行(因为默认情况下,数据内存可能没有执行权限)。 4. 将数组的地址转换为函数指针,然后调用该函数指针。 注意:这种方法需要谨慎操作,因为涉及到动态生成可执行代码,并且需要处理内存保护属性。 示例: 假设我们想执行一条简单的指令:`ret`(返回指令),其机器码为0xC3。 我们可以这样写: ```cpp #include <windows.h> int main() { // 1. 定义机器码数组 unsigned char code[] = { 0xC3 }; // ret // 2. 分配内存并设置可执行权限 // 注意:直接使用栈上的数组可能没有执行权限,因此我们需要使用VirtualAlloc等函数分配可执行内存 void* exec = VirtualAlloc(0, sizeof(code), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!exec) { // 错误处理 return 1; } // 3. 复制机器码到可执行内存 memcpy(exec, code, sizeof(code)); // 4. 将内存地址转换为函数指针(无参数、无返回值的函数) void (*func)() = (void(*)())exec; // 5. 调用函数 func(); // 6. 释放内存 VirtualFree(exec, 0, MEM_RELEASE); return 0; } ``` 但是,用户可能想要插入任意字节码,并且可能希望这些字节码能够与周围的C++代码交互(例如传递参数、返回值等)。因此,我们需要根据具体需求来设计。 另外,用户可能想要插入的字节码不是独立的函数,而是嵌入到函数中的一段代码。这种情况下,我们可以使用`__emit`关键字(在x86模式下可用,但在x64下不可用)。在x64下,我们可以使用编译器内部函数`__nop()`来插入特定的机器码,但`__nop()`只能插入0x90(NOP指令)。因此,对于任意字节码,我们需要使用上述方法,或者使用外部汇编器。 如果用户需要插入的字节码是作为函数的一部分,那么可能需要将整个函数用汇编语言编写在独立的.asm文件中,然后链接。 总结: 由于Visual Studio 2019x64模式不支持内联汇编,我们有两种方法: 方法一:使用独立的汇编文件(.asm)编写函数,然后通过项目设置将其汇编并链接。 方法二:在C++代码中嵌入机器码数组,并动态分配可执行内存来运行。 根据用户的具体需求,如果只是运行一段独立的机器码,方法二可行。如果是想在函数中内联一段机器码,则方法二可能不够直接,因为需要跳转到分配的内存去执行,然后再跳转回来,这比较复杂。此时,更推荐使用方法一。 下面,我们给出方法一的简要步骤: 1. 在项目中添加一个.asm文件,例如:asm_functions.asm 2. 编写汇编函数,例如: ```assembly ; asm_functions.asm .code my_function PROC ; 这里写汇编指令 ret my_function ENDP END ``` 3. 在C++代码中声明该函数: ```cpp extern "C" void my_function(); ``` 4. 在需要的地方调用该函数。 方法一需要配置项目以使用MASM(Microsoft Macro Assembler)。在项目属性中,将.asm文件设置为使用“Microsoft Macro Assembler”生成。 如果用户坚持要插入特定的字节码(而不是编写汇编指令),那么可以在.asm文件中使用`db`(定义字节)指令来直接插入字节码,例如: ```assembly my_function PROC db 0C3h ; 插入一个字节0xC3(ret指令) my_function ENDP ``` 因此,用户可以根据需要选择合适的方法。 相关问题: 1. 如何在Visual Studio 2019中配置x64汇编环境? 2. 如何将汇编函数与C++代码链接? 3. 如何编写x64汇编函数? 4. 如何将汇编指令转换为机器码? 5. 在C++中动态执行机器码有哪些安全注意事项? 6. 如何设置内存页为可执行? 7. 在x64汇编中,函数调用约定是怎样的? 8. 如何在汇编函数中传递参数和返回值? 9. 如何使用MASM汇编器? 10. 在x64汇编中,RIP相对寻址是什么?它有什么好处? 注意:由于用户的问题比较具体,我们给出了两种解决方案,并提供了示例代码。同时,我们生成了相关问题,以帮助用户深入理解。 引用说明: 在回答中,我们参考了用户提供的引用[1]和[2],它们涉及x64汇编和机器码的相关内容。特别是引用[1]提到了RIP相对寻址,引用[2]给出了机器码的例子和AT&T语法与Intel语法的区别。这些内容对于理解x64汇编和机器码是有帮助的,但我们的回答主要基于对Visual Studio 2019x64汇编支持情况的一般知识。 因此,在回答中我们并没有直接引用这些内容,而是根据已知知识给出了解决方案。 如果用户需要更详细的信息,可以查阅相关文档。 最终回答:</think>### 在 Visual Studio 2019 中插入 x64 汇编字节码的方法 由于 Visual Studio 2019 **不支持 x64 模式的内联汇编**(如 `__asm`),以下是两种可行的替代方案: --- ### 方法 1:通过 `.asm` 文件直接写入字节码(推荐) 1. **创建汇编文件** 在项目中添加 `.asm` 文件(如 `shellcode.asm`),使用 `db` 指令直接写入字节码: ```assembly ; shellcode.asm .code shellcode PROC db 0x48, 0xBA, 0xCF, 0xF7, 0x53, 0xE3, 0xA5 ; 你的字节码 ret shellcode ENDP END ``` 2. **配置项目属性** - 右键文件 → 属性 → 生成类型设为 **Microsoft Macro Assembler** - 平台选择 **x64** 3. **在 C++ 中调用** ```cpp extern "C" void shellcode(); int main() { shellcode(); // 调用字节码函数 return 0; } ``` --- ### 方法 2:动态内存注入(运行时写入) ```cpp #include <Windows.h> int main() { // 1. 定义字节码数组 unsigned char code[] = { 0x48, 0xBA, 0xCF, 0xF7, 0x53, 0xE3, 0xA5 // 你的字节码 }; // 2. 申请可执行内存 void* execMem = VirtualAlloc( NULL, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE // 关键:允许执行 ); memcpy(execMem, code, sizeof(code)); // 3. 转换为函数指针并执行 void (*func)() = (void(*)())execMem; func(); // 4. 释放内存 VirtualFree(execMem, 0, MEM_RELEASE); return 0; } ``` --- ### 关键注意事项 1. **内存权限** 必须使用 `PAGE_EXECUTE_READWRITE` 权限,否则会触发访问违规(0xC0000005)。 2. **字节码来源** - 使用反汇编工具(如 IDA、x64dbg)获取指令的原始字节码 - 示例:`movabs rdx, 0x20c49ba5e353f7cf` → `48 BA CF F7 53 E3 A5...` [^2] 3. **调试技巧** 在 `func()` 调用前设置断点,通过 VS 的 **内存窗口** 检查字节码是否正确写入。 4. **安全警告** 动态执行字节码可能被安全软件拦截,仅用于研究目的。 --- ### 相关问题 1. 如何在 x64 汇编中实现 RIP 相对寻址(RIP-relative addressing)?[^1] 2. 如何将 AT&T 语法汇编转换为机器码字节序列? 3. Visual Studio 中如何调试动态生成的机器码? 4. 为什么 x64 模式不再支持内联汇编?有哪些替代方案? 5. 如何确保注入的字节码与当前程序的地址空间兼容? > 提示:对于复杂字节码序列,建议先用 `.asm` 文件编写完整汇编逻辑,再通过编译后的二进制提取字节码。 [^1]: RIP 相对寻址简化了位置无关代码的实现,尤其在 shellcode 中避免绝对地址。 [^2]: 机器码语法参考 AT&T 与 Intel 格式差异,`movabs` 用于 64 位立即数操作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值