最近,我一直在为游戏模式编写一些x86汇编注入,但由于我的大部分工作流程都涉及手工编写和组装自定义例程,所以我一直在寻求更强大的解决方案
微软的内联汇编程序似乎是一个不错的选择,但我遇到了它似乎有的限制。
每当我写一条涉及直接内存地址的指令(游戏使用固定的地址空间布局)时,汇编器会默默地将其转换为立即值。
例如,在MASM中:
mov ecx, 0xCCCCCCCC => B9 CC CC CC CC
mov ecx, [0xCCCCCCCC] => B9 CC CC CC CC*
* Should be: 8B 0D CC CC CC CC
在这种情况下,两个汇编的指令都在加载具有立即值0xCCCCCCCC的ecx,尽管第二个指令应该从立即地址 0xCCCCCCCC
中获取值。请注意,可以这种方式使用命名变量:
mov ecx, [myInt]
将汇编为8B 0D内存提取指令,但它也会将操作数添加到模块的重定位表中,并且不允许指定任意地址。
试图用类似
的东西欺骗汇编程序mov ecx, [myInt-myInt+0xCCCCCCCC]
同时导致地址被视为立即值。
可以选择:
mov ecx, 0xCCCCCCCC
mov ecx, [ecx]
哪个会正确组装并显示正确的行为,但现在我的注射大小增加了2个不必要的字节。因为我在一些相当严格的空间限制下工作,这是不可接受的,我宁愿不使用我不需要的代码洞。
有趣的是C中的某些内容:
register int x;
x = *(int*)(0xCCCCCCCC)
快乐地编译到
mov ecx, [0xCCCCCCCC] => 8B 0D CC CC CC CC
看到较低级别的语言比较高级别的语言有更多限制,这有点奇怪。我正在尝试做的事情对我来说似乎很合理,所以有人知道MASM在从内存中读取时是否有一些隐藏的方式使用固定的直接内存地址?
答案 0 :(得分:1)
我不确定这是否可以在平面内存模型之外工作,但我发现MASM区分了直接地址和立即值,如下所示:
b
前2条指令使用立即值0xCCCCCCCC加载ecx。最后一条指令使用地址0xCCCCCCCC的值加载ecx。
答案 1 :(得分:1)
在NASM语法中,
mov ecx, 0xCCCCCCCC ; B9 CC CC CC CC mov ecx, imm32
mov ecx, [0xCCCCCCCC] ; 8b 0d cc cc cc cc mov r32, [disp32]
mov ecx, [_start-_start + 0xCCCCCCCC]; 8b 0d cc cc cc cc same
在我的GNU / Linux桌面上使用nasm -felf
和yasm -felf
进行了测试。
我想知道它是否是MASM将[0xCCCCCCCC]
组装成立即而不是有效地址的错误。当它是其他指令的操作数时,它是否也这样做?例如LEA
是错误的吗?