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.
But I noticed that when debugging within Visual Studio 2015, some memory location seems to be unchangeable as displayed in the Memory window.
For example:
In below picture, a function ApSignalMceToOs() begins at 0x7FFBBEE51360. I have unprotected the memory range 0x7FFBBEE51360 to 0x7FFBBEE5136E to modify it.
Line 305 to 312 modify the address range 0x7FFBBEE51360 ~ 0x7FFBBEE5136E.
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.
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.
So until this point, Visual Studio 2015 is telling me that my modification would fail.
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).
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:
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 disassembly code is decoded from the memory content. So the memory content or how VS2015 read/refresh it is the key point.
Based on above observation, I came to 2 conclusions with VS 2015 debug mode:
Some memory content is not correctly shown (or refreshed in GUI).
Some memory read operation doesn't work correctly.
But the program runs smoothly when not debugging.
Does anyone know why this is happening?
ADD 1 - 5:08 PM 10/14/2019
Thanks to #MichaelBurr. I guess I can explain it now.
The root cause is I added a breakpoint at 0x00007FFB...369 at the disassembly code level, not the C source level.
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.
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:
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.
But I think this very restoration doesn't make any sense. The restoration of the preserved byte content shouldn't be triggered at this moment in any way. A more reasonable action is to update the breakpoint's location a little bit and insert the 0xCC instruction to a new location. Because the newly modified code may change the "instruction boundary". This way, the debug experience of the self-modifying code can be best preserved. But this will require the Visual Studio to disassemble the new code in the nearby. And the new instruction content could be invalid if the programmer made a mistake.
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).
Related
I am reading this article about the SEH on Windows.
and here is the source code of myseh.cpp
I debugged myseh.cpp. I set 2 breakpoints at printf("Hello from an exception handler\n"); at line:24 and DWORD handler = (DWORD)_except_handler; at line: 36 respectively.
Then I ran it and it broke at line:36. I saw the stack trace as follows.
As going, AccessViolationException occurred because of mov [eax], 1
Then it broke at line:24. I saw the stack trace as follows.
The same thread but the frame of main was gone! Instead of _except_handle. And ESP jumped from 0018f6c8 to 0018ef34;it's a big gap between 0018f6c8 and 0018ef34
After Exception handled.
I know that _except_handle must be run at user mode rather than kernel mode.
After _except_handle returned, the thread turned to ring0 and then windows kernel modified CONTEXT EAX to &scratch & and then returned to ring3 . Thus thread ran continually.
I am curious about the mechanism of windows dealing with exception:
WHY the frame calling main was gone?
WHY the ESP jumped from 0018f6c8 to 0018ef34?(I mean a big pitch), Do those ESP address belong to same thread's stack??? Did the kernel play some tricks on ESP in ring3??? If so, WHY did it choose the address of 0018ef34 as handler callback's frame? Many thanks!
You are using the default debugger settings, not good enough to see all the details. They were chosen to help you focus on your own code and get the debug session started as quickly as possible.
The [External Code] block tells you that there are parts of the stack frame that do not belong to code that you have written. They don't, they belong to the operating system. Use Tools > Options > Debugging > General and untick the "Enable Just My Code" option.
The [Frames below might be incorrect...] warning tells you that the debugger doesn't have accurate PDBs to correctly walk the stack. Use Tools > Options > Debugging > Symbols and tick the "Microsoft Symbol Servers" option and choose a cache location. The debugger will now download the PDBs you need to debug through the operating system DLLs. Might take a while, it is only done once.
You can reason out the big ESP change, the CONTEXT structure is quite large and takes up space on the stack.
After these changes you ought to now see something resembling:
ConsoleApplication1942.exe!_except_handler(_EXCEPTION_RECORD * ExceptionRecord, void * EstablisherFrame, _CONTEXT * ContextRecord, void * DispatcherContext) Line 22 C++
ntdll.dll!ExecuteHandler2#20() Unknown
ntdll.dll!ExecuteHandler#20() Unknown
ntdll.dll!_KiUserExceptionDispatcher#8() Unknown
ConsoleApplication1942.exe!main() Line 46 C++
ConsoleApplication1942.exe!invoke_main() Line 64 C++
ConsoleApplication1942.exe!__scrt_common_main_seh() Line 255 C++
ConsoleApplication1942.exe!__scrt_common_main() Line 300 C++
ConsoleApplication1942.exe!mainCRTStartup() Line 17 C++
kernel32.dll!#BaseThreadInitThunk#12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart#8() Unknown
Recorded on Win10 version 1607 and VS2015 Update 2. This isn't the correct way to write SEH handlers, find a better example in this post.
I would like to understand how Turbo Debugger works. So, for example, I have a message and I moved it to the DX register.
(I show you how it looks in the debugger):
MOV DX,009E ;This is a version which debugger shows me in debugger mode;
;It takes all information from this code: MOV DX,OFFSET MSG.
In fact, the message's first element address is at 9E (this is how the debugger understands). But actually, in the debugger screen, I can see that in the DS register, MSG address is at A0. How can it be?
I know that code is more preferable, but this time a screenshot is more suitable:
As you can see, I marked 2 addresses, but they are not the same. Actually, I can see that my MSG begins in the above-marked address A0, but that the debugger understands it like 9E and moves it to DX. Can someone explain to me how this can be?
By the way, the program works and prints everything fine, the purpose is to understand how the debugger understands addresses.
MSG code is simply:
MSG db 'Hello, how do you do!!!!,'$'
I believe that if you will single step your code, instruction by instruction, you will see that
You are correct that that your message starts at DS:00A0
Turbo Debugger is also correct that it starts two bytes before that
Look carefully at what is located at DS:009E.
What do you see there ? Two bytes: 0A and 0D
That's an ascii "Line Feed" and an Ascii "Carriage Return".
Your confusion can be reduced by understanding the historical perspective...
Way back when printers used ink and paper, and telephones carried modem signals at 1200 BPS, and you paid something like ten hours of minimum wage pay for one hour of that connection to a city only three states away, there really was an economic imperative in choosing between running the little print head back to the left, or just jacking the platen down a line while the print head stayed in the same position.
I mean, you really saw it in your phone bill.
No joke, this one change, using the 0A byte without the 0D byte, could mean a 10 or 20 dollar difference in your phone bill; and remember to factor in inflation back then.
The reason that you see the message properly is because your machine is first placing a "line feed" (i.e., the cursor is probably dropping to the next line) and a "carriage return" (i.e., the cursor jumps back to the left edge) before putting your message on the screen. This happens much faster than your eye can see.
With the miracle of Turbo Debugger, you can single step this and watch it happen.
So, you are correct when you write that your message "starts" at 00A0, but Turbo Debugger is also right when it's telling you that the message starts two bytes ahead of that.
How does a debugger set breakpoints if the image is in read-only memory? I know there are hardware breakpoints, but in the debugger I use (OllyDbg) those have to be set specially using a different dialog than normal breakpoints.
Explanation:
Here is a routine in a debugger that is comparing itself to a copy of itself. EDX points to the running image, EBX points to the known good copy of the image. The breakpoint on 4010CE only is reached if there is a mismatch. The character being compared is in the AL register. As you can see the debugger shows EB F6 at 10CE, but this is false. 10CE actually has CC in it, as you can see by looking at the AL register. This is because the debugger has secretely inserted the CC to perform the breakpoint.
The debugger first has to change the memory protection of the page it wants to write to. This can be done with VirtualProtectEx. After that it is able to write with WriteProcessMemory and then set the protection back to the original value.
Let me preface this with a disclaimer that I'm not familiar with your particular toolset.
If you haven't enabled hardware breakpoints, the only remaining breakpoint type is a software breakpoint. These are only hit (on x86 because that's what I'm most familiar with) when you replace the first byte of an instruction with a trap instruction, and will only be routed through the breakpoint mechanism of your OS to your debugger if the correct trap instruction for your OS is used and the debugger has already registered itself with the OS as a debugger for this process. In order to cause the software breakpoint to happen at the correct moment, the trap instruction must be written into your code segment over the first byte of your correct instruction.
The two answers that got here first explain the two scenarios which could get you here (at least, the only two I can think of):
The kernel always has write access everywhere, except for hardware-protected pages (ie on some sort of ROM), which your process' memory is almost certainly not. It has the ability to write the breakpoint instruction regardless of the permissions exposed to the user process being debugged.
The debugger must use some syscall to change the access rights on the memory of the target process before inserting the breakpoint.
Personally, I'm guessing the first thing is happening. The segment permissions are only in place to protect your target process from itself, not from a debugger process or from the kernel. Debugging mechanisms in operating systems pretty regularly violate "normal" permissions to allow the debugger to do whatever it wants to the target process. This, of course, is why some operating systems require you to enter a password before you're allowed to use the debugger in certain scenarios.
However, you can test if it's the second one by attempting to write to the code segment from inside the target process after a breakpoint has been set. If the write succeeds, you know the permissions have been lowered by the OS (to allow the process to be debugged). It would be pretty awkward for the OS to require a debugger to jump through this hoop since it can already insert arbitrary code into the writeable parts of memory and then force a jump to it by generating a stack frame overflow.
The debugger takes advantage of the WriteProcessMemory() function to alter the instruction in place. It'll keep a copy of the instruction. When the bp is hit it will reset the old byte value and set EIP back to the previous instruction so the real instruction can execute.
I want to debug into the implementation of a [MethodImpl(MethodImplOptions.InternalCall)] BCL method, which is presumably implemented in C++. (In this particular case, I'm looking at System.String.nativeCompareOrdinal.) This is mainly because I'm nosy and want to know how it's implemented.
However, the Visual Studio debugger is refusing to step into that method. I can set a breakpoint on this call:
"Hello".Equals("hello", StringComparison.OrdinalIgnoreCase);
then bring up Debug > Windows > Disassembly, step into the Equals call, and step until it gets to the call x86 instruction. But when I try to use "Step Into" on that call (which I know from Reflector is the nativeCompareOrdinal call), it doesn't step to the first instruction inside nativeCompareOrdinal like I want -- it steps over instead, and goes straight to the next x86 instruction in Equals.
I'm building as x86, since mixed-mode debugging isn't supported for x64 apps. I've unchecked "Just My Code" in Tools > Options > Debugging, and I have "Enable unmanaged code debugging" checked in project properties > Debug tab, but it still steps over the call. I also tried starting the process and then attaching the debugger, and explicitly attaching both the managed and native debuggers, but it still won't step into that InternalCall method.
How can I get the Visual Studio debugger to step into an unmanaged method?
Yes, it is tricky. The offset you see for the CALL instruction is bogus. Plus it won't let you navigate to an unmanaged code address when the current focus is on a managed function.
Start by enabling unmanaged code debugging and setting a breakpoint on the call. Run the code and when the break point hits use Debug + Windows + Disassembly:
"Hello".Equals("hello", StringComparison.OrdinalIgnoreCase);
00000025 call 6E53D5D0
0000002a nop
The debugger tries to display the absolute address but gets it wrong because it uses the bogus incremental address instead of the real instruction address. So first recover the true relative value: 0x6E53D5D0 - 0x2A = 0x6E53D5A6.
Next you need to find the real code address. Debug + Windows + Registers and look at the value of the EIP register. 0x009A0095 in my case. Add 5 to get to the nop, then add the relative offset: 0x9A0095 + 5 + 0x6E53D5A6 = 0x6EEDD640. The real address of the function.
Debug + Windows + Call Stack and double-click an unmanaged stack frame. Now you can enter the calculated address in the Disassembly window's Address box, prefix with 0x.
6EEDD640 push ebp
6EEDD641 mov ebp,esp
6EEDD643 push edi
6EEDD644 push esi
6EEDD645 push ebx
6EEDD646 sub esp,18h
etc...
Bingo, you're know you're good if you see the stack frame setup code. Set a breakpoint on it and press F5.
Of course, you'll be stepping machine code since there's no source code available. You'll get much better insight in what this code is doing by looking at the SSCLI20 source code. No guarantee that it will be a match for the actual code in your current version of the CLR but my experience is that these low-level code chunks that have been around since 1.0 are highly conserved. The implementation is in clr\src\classlibnative\nls, not sure which source code file. It won't be named "nativeCompareOrdinal", that's just an internal name used by ecall.cpp.
I'm debugging some code from the disassembly (no source code is available), and there a number of instructions accessing data via the ds segment register, e.g. something like this:
66 3B 05 8A B1 43 00 cmp ax,word ptr ds:[43B18Ah]
How do you get the Visual Studio debugger to tell you the offset of the ds segment register so that I can inspect the memory this is referring to? The Watch window does not seem to accept expressions like ds:[0x43B18A] or variants; it will tell me that ds is 0, but that doesn't tell me what segment 0's offset is.
Is there some special syntax for this, or is this something that VS just can't do? Would I have better luck with another debugger, such as WinDbg or ntsd?
This is a quirk of the disassembler built into Visual Studio. It is superfluous, the DS register is the default. Just ignore it, on Windows the DS, CS and ES registers are set to the same value. A protected mode selector. And the same value used by the Memory window. Just omit the ds: prefix.