问题描述
我正在编写一些多线程C程序.我试图修改函数主体开头的一些指令,以将执行重定向到其他地方.
I am writing some multi-thread C program. I tried to modify the few instructions at the beginning of a function's body to redirect the execution to somewhere else.
但是我注意到在Visual Studio 2015中进行调试时,某些内存位置似乎不可更改,如Memory
窗口中所示.
But I noticed that when debugging within Visual Studio 2015, some memory location seems to be unchangeable as displayed in the Memory
window.
例如:
在下图中,功能ApSignalMceToOs()
从0x7FFBBEE51360
开始.我已取消保护0x7FFBBEE51360
至0x7FFBBEE5136E
的内存范围以对其进行修改.
In below picture, a function ApSignalMceToOs()
begins at 0x7FFBBEE51360
. I have unprotected the memory range 0x7FFBBEE51360
to 0x7FFBBEE5136E
to modify it.
第305行至312行修改地址范围0x7FFBBEE51360
〜0x7FFBBEE5136E
.
Line 305 to 312 modify the address range 0x7FFBBEE51360
~ 0x7FFBBEE5136E
.
一切正常,直到0x7FFBBEE51369
.在第311行,(uint32_t(((uintptr_t)dst) >> 32
是0x00007ffb
.在执行第311行之后,我期望0x7FFBBEE51369
〜0x7FFBBEE5136C
中的内存范围将被填充为fb 7f 00 00
.但是如下所示,Visual Studio表示它是48 7f 00 00
,其中48
是旧值.
Everything is fine until 0x7FFBBEE51369
. At line 311, the (uint32_t(((uintptr_t)dst) >> 32
is 0x00007ffb
.After line 311 is executed, I was expecting the memory range in 0x7FFBBEE51369
~ 0x7FFBBEE5136C
will be filled as fb 7f 00 00
. But as shown below, Visual Studio says it is 48 7f 00 00
, where the 48
is the old value.
然后我去检查函数ApSignalMceToOs()
的反汇编代码.毫不奇怪,00007FFBBF171365
处的指令是mov dword ptr [rsp+4], 7F48h
,应该应为7FFB
.如下面的红色框中所示.
Then I went to check the disassembly code of the function ApSignalMceToOs()
. And not surprisingly, the instruction at 00007FFBBF171365
is mov dword ptr [rsp+4], 7F48h
, which should be 7FFB
. As shown below in the red box below.
因此,在这一点上,Visual Studio 2015告诉我,修改将会失败.
So until this point, Visual Studio 2015 is telling me that my modification would fail.
但是如上图中的黄色箭头所示,在执行mov dword ptr [rsp+4], 7F48h
后,我检查了堆栈区域中的内容. 令人惊讶的是确实是7f fb
被移到了堆栈上(显示在上方图片的绿色框中).
But as the yellow arrow in above picture shows, after the mov dword ptr [rsp+4], 7F48h
is executed, I checked the content in the stack area. Surprisingly it is indeed 7f fb
got moved onto the stack (shown in the green box in above picture).
在执行ret
指令后,RIP
寄存器的确更改为00007FFBBEEAD940
,这不足为奇.见下文:
And after the ret
instruction is executed, the RIP
register does change to 00007FFBBEEAD940
, which is no surprise. See below:
在另一个函数中,正在读取相同的位置.如下图所示:
And in another function, the same location is being read. Shown as below:
code[len]
或byte ptr [rax]
是保存48
或fb
的存储位置.但是它读取的是0xcc
,它既不是0x48
也不是0xfb
.
The code[len]
or byte ptr [rax]
is the memory location holding 48
or fb
. But it reads 0xcc
, which is neither 0x48
nor 0xfb
.
Visual Studio反汇编代码从内存内容中解码.因此,内存内容或 VS2015如何读取/刷新它是关键.
Visual Studio disassembly code is decoded from the memory content. So the memory content or how VS2015 read/refresh it is the key point.
基于上述观察,我得出了VS 2015调试模式的2个结论:
Based on above observation, I came to 2 conclusions with VS 2015 debug mode:
- 某些内存内容未正确显示(或在GUI中刷新).
- 某些内存读取操作无法正常工作.
但是该程序在未调试时运行平稳.
有人知道为什么会这样吗?
Does anyone know why this is happening?
感谢@MichaelBurr.我想我现在可以解释它.
Thanks to @MichaelBurr. I guess I can explain it now.
根本原因是我在反汇编代码级别(而不是C源代码级别)的0x00007FFB...369
处添加了一个断点.
The root cause is I added a breakpoint at 0x00007FFB...369
at the disassembly code level, not the C source level.
当我这样做时,VS调试器 did 在0x00007FFB...369
位置添加了0xCC
指令.但是 Visual Studio 2015竭尽全力隐藏这一事实.下面是断点位于0x00007FFB...369
的内存内容的显示,我们可以看到0x00007FFB...369
仍然保留旧值0x48
.
When I did this, the VS Debugger did add a 0xCC
instruction at the location 0x00007FFB...369
. But it seems Visual Studio 2015 goes to great lengths to hide this fact. Below is the show of the memory content with the breakpoint at 0x00007FFB...369
, we can see 0x00007FFB...369
still holds the old value 0x48
.
但是在我将内存从0x00007FFB...360
手动复制到0x00007FFB...36e
到其他地方之后.偏移量为0x9
的0xCC
指令已公开.见下文:
But after I manually copied the memory from 0x00007FFB...360
to 0x00007FFB...36e
to somewhere else. The 0xCC
instruction at the offset 0x9
is unveiled. See below:
当我在0x00007FFB...369
处修改内容时,Visual Studio似乎收到了警报,它只是将内容还原到了旧的保存内容,即0x48
.不是我新写的.
When I modify the content at 0x00007FFB...369
, Visual Studio seemed to be alerted and it just restored the content to the old preserved one, i.e. 0x48
. Not my newly written one.
但是我认为这种恢复没有任何意义.此时不应以任何方式触发对保留的字节内容的恢复.一个更合理的操作是稍微更新断点的位置,然后将0xCC指令插入到新位置.因为新修改的代码可能会更改指令边界".这样,可以最好地保留自修改代码的调试体验.但这将要求Visual Studio在附近分解新代码.如果程序员犯了错误,那么新的指令内容可能无效.
推荐答案
我认为您实质上是在与调试器的断点/单步处理作斗争.断点通常使用int 3
指令实现,该指令的编码为0xCC
.当调试器为断点设置0xCC
时,它必须保存原始值,然后在调试器停止程序执行时将其替换.
I think you are essentially fighting with the debugger's breakpoint/single step handling. Breakpoints are often implemented with the int 3
instruction which has the encoding 0xCC
. When the debugger sets the 0xCC
for the breakpoint it has to save the original value, then replace it when the debugger has stopped program execution.
在正常情况下(未经自我修改的代码),这会使事情在检查代码存储区时如您所愿.但是,如果您的程序修改了调试器管理的内存,则可能会导致混淆,因为调试器将还原设置断点时保存的值(覆盖您的修改).
In a normal situation (code that isn't self-modified) this makes things appear as you expect when examining the code memory region. However if your program modifies the memory that is being managed by the debugger you can get confusing results since the debugger will restore the value it had saved when it set the breakpoint (overwriting your modification).
这篇关于在Visual Studio调试模式下显示奇怪的内存内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!