How would I go about monitoring Kernel callbacks? I am specifically interested in monitoring the callback functions from the Kernel callback table. I am trying to figure out which user32 API call triggers which callback function.
I do not believe I can see these calls using a debugger, so would an option be ETW tracing?
I did some quick tests (on Windows 10) using the kernel debugger since it's pretty much needed to get which user calls ends up in which callback function.
I'm using notepad.exe as a target since it has a GUI.
2: kd> !process 0 0 notepad.exe
PROCESS ffffb987185d9080
SessionId: 1 Cid: 20ec Peb: c21923b000 ParentCid: 141c
DirBase: 5510e002 ObjectTable: ffffa80636fcf340 HandleCount: 239.
Image: notepad.exe
the _EPROCESS structure is at 0xffffb987185d9080 and its _PEB is at 0xc21923b000. The first one will be useful to put a breakpoint just for notepad.exe and the second one to have a view on the kernel call back table.
Setting a BP on nt!KeUserModeCallback
2: kd> bp /p ffffb987185d9080 nt!KeUserModeCallback; g
We know that the first parameter for this function is an index into the kernel callback table:
NTSTATUS KeUserModeCallback (
IN ULONG ApiNumber,
IN PVOID InputBuffer,
IN ULONG InputLength,
OUT PVOID *OutputBuffer,
IN PULONG OutputLength
);
The kernel callback table is accesssible directly from the _PEB structure, using the KernelCallbackTable field:
1: kd> dt _peb c21923b000 KernelC*
wintypes!_PEB
+0x058 KernelCallbackTable : 0x00007ffc`12831070 Void
1: kd> dps 0x00007ffc`12831070
00007ffc`12831070 00007ffc`127c2710 USER32!_fnCOPYDATA
00007ffc`12831078 00007ffc`128299f0 USER32!_fnCOPYGLOBALDATA
00007ffc`12831080 00007ffc`127c0b90 USER32!_fnDWORD
00007ffc`12831088 00007ffc`127c69f0 USER32!_fnNCDESTROY
00007ffc`12831090 00007ffc`127cda60 USER32!_fnDWORDOPTINLPMSG
00007ffc`12831098 00007ffc`1282a220 USER32!_fnINOUTDRAG
00007ffc`128310a0 00007ffc`127c7f20 USER32!_fnGETTEXTLENGTHS
00007ffc`128310a8 00007ffc`12829ec0 USER32!_fnINCNTOUTSTRING
00007ffc`128310b0 00007ffc`12829f80 USER32!_fnINCNTOUTSTRINGNULL
00007ffc`128310b8 00007ffc`127c9690 USER32!_fnINLPCOMPAREITEMSTRUCT
00007ffc`128310c0 00007ffc`127c2b70 USER32!__fnINLPCREATESTRUCT
00007ffc`128310c8 00007ffc`1282a040 USER32!_fnINLPDELETEITEMSTRUCT
00007ffc`128310d0 00007ffc`127cfdf0 USER32!__fnINLPDRAWITEMSTRUCT
00007ffc`128310d8 00007ffc`1282a0a0 USER32!_fnINLPHELPINFOSTRUCT
00007ffc`128310e0 00007ffc`1282a0a0 USER32!_fnINLPHELPINFOSTRUCT
00007ffc`128310e8 00007ffc`1282a1a0 USER32!_fnINLPMDICREATESTRUCT
It's interesting to see that this table also have a symbolic name, namely USER32!apfnDispatch:
1: kd> ln 0x00007ffc`12831070
(0x00007ffc`12831070) USER32!apfnDispatch
1: kd> ? USER32!apfnDispatch
Evaluate expression: 140720619065456 = 00007ffc`12831070
With all this we can set a logging breakpoint on nt!KeUserModeCallback:
1: kd> bp /p ffffb987185d9080 nt!KeUserModeCallback ".printf \"RCX: %p --> %y\\n\", #rcx, poi(user32!apfnDispatch + (#rcx * 8)); k; g"
This prints the ApiNumber (in RCX) and the name of the function associated to the number from the kernel callback table, followed by a stack trace. Dump example:
RCX: 0000000000000016 --> USER32!_fnINOUTLPPOINT5 (00007ffc`127c3d30)
# Child-SP RetAddr Call Site
00 ffffb80f`ac76dd08 fffffe32`37a3d2ef nt!KeUserModeCallback
01 ffffb80f`ac76dd10 fffffe32`37a095d4 win32kfull!SfnINOUTLPWINDOWPOS+0x29f
02 ffffb80f`ac76de50 fffffe32`37a091c2 win32kfull!xxxSendMessageToClient+0x114
03 ffffb80f`ac76df10 fffffe32`379e0ed9 win32kfull!xxxSendTransformableMessageTimeout+0x282
04 ffffb80f`ac76e060 fffffe32`379df20c win32kfull!xxxCalcValidRects+0x32d
05 ffffb80f`ac76e200 fffffe32`379ac9c5 win32kfull!xxxEndDeferWindowPosEx+0x1ac
06 ffffb80f`ac76e2e0 fffffe32`37a25033 win32kfull!xxxProcessDesktopRecalc+0x221
07 ffffb80f`ac76e3b0 fffffe32`37a261e8 win32kfull!xxxProcessEventMessage+0x39b
08 ffffb80f`ac76e6e0 fffffe32`37a06211 win32kfull!xxxScanSysQueue+0xd48
09 ffffb80f`ac76ef20 fffffe32`37a050e2 win32kfull!xxxRealInternalGetMessage+0xef1
0a ffffb80f`ac76f3f0 fffffe32`373e6276 win32kfull!NtUserGetMessage+0x92
0b ffffb80f`ac76f480 fffff805`28c08bb5 win32k!NtUserGetMessage+0x16
0c ffffb80f`ac76f4c0 00007ffc`11b11104 nt!KiSystemServiceCopyEnd+0x25
0d 000000c2`1947fa08 00007ffc`127c1b3e win32u!NtUserGetMessage+0x14
0e 000000c2`1947fa10 00007ff6`0803c3ac USER32!GetMessageW+0x2e
0f 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
10 000000c2`1947fb20 00007ffc`131b7034 notepad!__scrt_common_main_seh+0x106
11 000000c2`1947fb60 00007ffc`14022651 KERNEL32!BaseThreadInitThunk+0x14
12 000000c2`1947fb90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
RCX: 000000000000001b --> USER32!_fnINSTRING (00007ffc`127c1ce0)
# Child-SP RetAddr Call Site
00 ffffb80f`ac76dda8 fffffe32`37997895 nt!KeUserModeCallback
01 ffffb80f`ac76ddb0 fffffe32`37a095d4 win32kfull!SfnINSTRINGNULL+0x2b5
02 ffffb80f`ac76e140 fffffe32`37a091c2 win32kfull!xxxSendMessageToClient+0x114
03 ffffb80f`ac76e200 fffffe32`37a0cc10 win32kfull!xxxSendTransformableMessageTimeout+0x282
04 ffffb80f`ac76e350 fffffe32`37a24ebd win32kfull!xxxSendMessage+0x2c
05 ffffb80f`ac76e3b0 fffffe32`37a261e8 win32kfull!xxxProcessEventMessage+0x225
06 ffffb80f`ac76e6e0 fffffe32`37a06211 win32kfull!xxxScanSysQueue+0xd48
07 ffffb80f`ac76ef20 fffffe32`37a050e2 win32kfull!xxxRealInternalGetMessage+0xef1
08 ffffb80f`ac76f3f0 fffffe32`373e6276 win32kfull!NtUserGetMessage+0x92
09 ffffb80f`ac76f480 fffff805`28c08bb5 win32k!NtUserGetMessage+0x16
0a ffffb80f`ac76f4c0 00007ffc`11b11104 nt!KiSystemServiceCopyEnd+0x25
0b 000000c2`1947fa08 00007ffc`127c1b3e win32u!NtUserGetMessage+0x14
0c 000000c2`1947fa10 00007ff6`0803c3ac USER32!GetMessageW+0x2e
0d 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
0e 000000c2`1947fb20 00007ffc`131b7034 notepad!__scrt_common_main_seh+0x106
0f 000000c2`1947fb60 00007ffc`14022651 KERNEL32!BaseThreadInitThunk+0x14
10 000000c2`1947fb90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
RCX: 000000000000006a --> USER32!_fnINLPUAHDRAWMENU (00007ffc`127c61b0)
# Child-SP RetAddr Call Site
00 ffffb80f`ad457888 fffffe32`37a4e22d nt!KeUserModeCallback
01 ffffb80f`ad457890 fffffe32`37a095d4 win32kfull!SfnINLPUAHDRAWMENU+0x20d
02 ffffb80f`ad4579c0 fffffe32`37a091c2 win32kfull!xxxSendMessageToClient+0x114
03 ffffb80f`ad457a80 fffffe32`37a0cc10 win32kfull!xxxSendTransformableMessageTimeout+0x282
04 ffffb80f`ad457bd0 fffffe32`379a852f win32kfull!xxxSendMessage+0x2c
05 ffffb80f`ad457c30 fffffe32`379a81b8 win32kfull!xxxSendUAHMenuMessage+0x3f
06 ffffb80f`ad457c80 fffffe32`379a6a45 win32kfull!xxxPaintMenuBar+0x174
07 ffffb80f`ad457d20 fffffe32`373e7152 win32kfull!NtUserPaintMenuBar+0xe5
08 ffffb80f`ad457d80 fffff805`28c08bb5 win32k!NtUserPaintMenuBar+0x2a
09 ffffb80f`ad457dd0 00007ffc`11b12c64 nt!KiSystemServiceCopyEnd+0x25
0a 000000c2`1947efd8 00007ffc`0f12a919 win32u!NtUserPaintMenuBar+0x14
0b 000000c2`1947efe0 00007ffc`0f1271f4 uxtheme!CThemeWnd::NcPaint+0x239
0c 000000c2`1947f130 00007ffc`0f12b809 uxtheme!OnDwpNcActivate+0x54
0d 000000c2`1947f170 00007ffc`0f12b271 uxtheme!_ThemeDefWindowProc+0x589
0e 000000c2`1947f350 00007ffc`127ac7e3 uxtheme!ThemeDefWindowProcW+0x11
0f 000000c2`1947f390 00007ff6`0803bb57 USER32!DefWindowProcW+0x1a3
10 000000c2`1947f3f0 00007ffc`127ae858 notepad!NPWndProc+0x557
11 000000c2`1947f730 00007ffc`127ae3dc USER32!UserCallWinProcCheckWow+0x2f8
12 000000c2`1947f8c0 00007ffc`127c0bc3 USER32!DispatchClientMessage+0x9c
13 000000c2`1947f920 00007ffc`14070c54 USER32!_fnDWORD+0x33
14 000000c2`1947f980 00007ffc`11b11104 ntdll!KiUserCallbackDispatcherContinue
15 000000c2`1947fa08 00007ffc`127c1b3e win32u!NtUserGetMessage+0x14
16 000000c2`1947fa10 00007ff6`0803c3ac USER32!GetMessageW+0x2e
17 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
18 000000c2`1947fb20 00007ffc`131b7034 notepad!__scrt_common_main_seh+0x106
19 000000c2`1947fb60 00007ffc`14022651 KERNEL32!BaseThreadInitThunk+0x14
1a 000000c2`1947fb90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
RCX: 000000000000006b --> USER32!__fnINLPUAHDRAWMENUITEM (00007ffc`127c4190)
# Child-SP RetAddr Call Site
00 ffffb80f`ad457538 fffffe32`37a4e835 nt!KeUserModeCallback
01 ffffb80f`ad457540 fffffe32`37a095d4 win32kfull!SfnINLPUAHDRAWMENUITEM+0x255
02 ffffb80f`ad457700 fffffe32`37a091c2 win32kfull!xxxSendMessageToClient+0x114
03 ffffb80f`ad4577c0 fffffe32`37a0cc10 win32kfull!xxxSendTransformableMessageTimeout+0x282
04 ffffb80f`ad457910 fffffe32`379ab397 win32kfull!xxxSendMessage+0x2c
05 ffffb80f`ad457970 fffffe32`379ab118 win32kfull!xxxSendMenuDrawItemMessage+0x17f
06 ffffb80f`ad457ab0 fffffe32`379aaf34 win32kfull!xxxDrawMenuItem+0x130
07 ffffb80f`ad457b80 fffffe32`379a8203 win32kfull!xxxMenuDraw+0x224
08 ffffb80f`ad457c80 fffffe32`379a6a45 win32kfull!xxxPaintMenuBar+0x1bf
09 ffffb80f`ad457d20 fffffe32`373e7152 win32kfull!NtUserPaintMenuBar+0xe5
0a ffffb80f`ad457d80 fffff805`28c08bb5 win32k!NtUserPaintMenuBar+0x2a
0b ffffb80f`ad457dd0 00007ffc`11b12c64 nt!KiSystemServiceCopyEnd+0x25
0c 000000c2`1947efd8 00007ffc`0f12a919 win32u!NtUserPaintMenuBar+0x14
0d 000000c2`1947efe0 00007ffc`0f1271f4 uxtheme!CThemeWnd::NcPaint+0x239
0e 000000c2`1947f130 00007ffc`0f12b809 uxtheme!OnDwpNcActivate+0x54
0f 000000c2`1947f170 00007ffc`0f12b271 uxtheme!_ThemeDefWindowProc+0x589
10 000000c2`1947f350 00007ffc`127ac7e3 uxtheme!ThemeDefWindowProcW+0x11
11 000000c2`1947f390 00007ff6`0803bb57 USER32!DefWindowProcW+0x1a3
12 000000c2`1947f3f0 00007ffc`127ae858 notepad!NPWndProc+0x557
13 000000c2`1947f730 00007ffc`127ae3dc USER32!UserCallWinProcCheckWow+0x2f8
14 000000c2`1947f8c0 00007ffc`127c0bc3 USER32!DispatchClientMessage+0x9c
15 000000c2`1947f920 00007ffc`14070c54 USER32!_fnDWORD+0x33
16 000000c2`1947f980 00007ffc`11b11104 ntdll!KiUserCallbackDispatcherContinue
17 000000c2`1947fa08 00007ffc`127c1b3e win32u!NtUserGetMessage+0x14
18 000000c2`1947fa10 00007ff6`0803c3ac USER32!GetMessageW+0x2e
19 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
1a 000000c2`1947fb20 00007ffc`131b7034 notepad!__scrt_common_main_seh+0x106
1b 000000c2`1947fb60 00007ffc`14022651 KERNEL32!BaseThreadInitThunk+0x14
1c 000000c2`1947fb90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
It get a bit more complicated if you have a function like user32!GetMessageW where the callback function depends on the argument passed to GetMessageW.
In this case you need to get back to the frame where it is called:
RCX: 000000000000001c --> USER32!__fnINDEVICECHANGE (00007ffc`127cdd70)
# Child-SP RetAddr Call Site
00 ffffb80f`ac76e8a8 fffffe32`37999cab nt!KeUserModeCallback
01 ffffb80f`ac76e8b0 fffffe32`37a095d4 win32kfull!SfnINDEVICECHANGE+0x28b
02 ffffb80f`ac76ec40 fffffe32`37a08634 win32kfull!xxxSendMessageToClient+0x114
03 ffffb80f`ac76ed00 fffffe32`37a06078 win32kfull!xxxReceiveMessage+0x3b4
04 ffffb80f`ac76ef20 fffffe32`37a050e2 win32kfull!xxxRealInternalGetMessage+0xd58
05 ffffb80f`ac76f3f0 fffffe32`373e6276 win32kfull!NtUserGetMessage+0x92
06 ffffb80f`ac76f480 fffff805`28c08bb5 win32k!NtUserGetMessage+0x16
07 ffffb80f`ac76f4c0 00007ffc`11b11104 nt!KiSystemServiceCopyEnd+0x25
08 000000c2`1947fa08 00007ffc`127c1b3e win32u!NtUserGetMessage+0x14
09 000000c2`1947fa10 00007ff6`0803c3ac USER32!GetMessageW+0x2e
0a 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
0b 000000c2`1947fb20 00007ffc`131b7034 notepad!__scrt_common_main_seh+0x106
0c 000000c2`1947fb60 00007ffc`14022651 KERNEL32!BaseThreadInitThunk+0x14
0d 000000c2`1947fb90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Le'ts get back the the frame where the function is called (frame 0xa):
1: kd> .frame /r 0xa
0a 000000c2`1947fa70 00007ff6`080559b6 notepad!wWinMain+0x2b4
rax=ffffb80fac76e8e4 rbx=000002870361237c rcx=000000000000001c
rdx=ffffb80fac76ea00 rsi=00007ff608030000 rdi=0000000000000000
rip=00007ff60803c3ac rsp=000000c21947fa70 rbp=000000c21947fab9
r8=0000000000000068 r9=ffffb80fac76e908 r10=0000000000000000
r11=ffffb80fac76e800 r12=0000000000000000 r13=0000000000000000
r14=0000000000020375 r15=00007ff608030000
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
notepad!wWinMain+0x2b4:
00007ff6`0803c3ac 0f1f440000 nop dword ptr [rax+rax]
Here's the disassembly:
00007ff6`0803c399 4533c9 xor r9d,r9d
00007ff6`0803c39c 488d4d0f lea rcx,[rbp+0Fh]
00007ff6`0803c3a0 4533c0 xor r8d,r8d
00007ff6`0803c3a3 33d2 xor edx,edx
00007ff6`0803c3a5 48ff15f4c80100 call qword ptr [notepad!_imp_GetMessageW (00007ff6`08058ca0)]
00007ff6`0803c3ac 0f1f440000 nop dword ptr [rax+rax] ; frame pointer here
The 1st argument to GetMessageW is a pointer to a MSG structure so you can see it comes from RBP+0x0f in this case:
1: kd> db 000000c21947fab9 + f
000000c2`1947fac8 10 03 03 00 00 00 00 00-00 04 00 00 00 00 00 00 ................
000000c2`1947fad8 be ba 00 00 00 00 00 00-c0 2f 67 03 87 02 00 00 ........./g.....
000000c2`1947fae8 96 6e 07 00 ab 02 00 00-80 01 00 00 00 00 00 00 .n..............
000000c2`1947faf8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
000000c2`1947fb08 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
000000c2`1947fb18 b6 59 05 08 f6 7f 00 00-01 00 00 00 00 00 00 00 .Y..............
000000c2`1947fb28 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
000000c2`1947fb38 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
In this case the WM_ message is 0x400.
Beside the kernel debugger, it's interesting to see that all calls to nt!KeUserModeCallback are surrounded by calls to nt!EtwTraceBeginCallback and nt!EtwTraceEndCallback (below an example from win32Kfull.sys in the fnHkINLPMSG function)
.text:00000001C009D429 call cs:__imp_EtwTraceBeginCallback
.text:00000001C009D430 nop dword ptr [rax+rax+00h]
.text:00000001C009D435 lea rax, [rsp+158h+arg_10]
.text:00000001C009D43D mov [rsp+158h+BugCheckParameter4], rax
.text:00000001C009D442 lea r9, [rsp+158h+var_110]
.text:00000001C009D447 mov r8d, 58h ; 'X'
.text:00000001C009D44D lea rdx, [rsp+158h+var_E8]
.text:00000001C009D452 lea ecx, [r8-29h]
.text:00000001C009D456 call cs:__imp_KeUserModeCallback
.text:00000001C009D45D nop dword ptr [rax+rax+00h]
.text:00000001C009D462 mov r12d, eax
.text:00000001C009D465 mov ecx, 2Fh ; '/'
.text:00000001C009D46A call cs:__imp_EtwTraceEndCallback
So using ETW is definitely a possibility. Although I haven't tested it, I suspect the output from the event is quite "raw" without any mention of function names, so it probably requires more work after getting the output from ETW.
I would like to see the first few instructions that my machine executes at startup. On x64 the reset vector is at physical address FFFFFFF0. I have enabled local kernel debugging on my Windows 10, restarted the PC and started WinDbg as Administrator. When doing a kernel debug (File -> Kernel Debug...), I am not sure what to type at the lkd> prompt to unassemble the code. I can do "!db FFFFFFF0" which displays some bytes:
#fffffff0 90 90 e9 83 e8 00 00 00-fc 00 00 00 00 00 e1 ff ................
#100000000 bb 00 fc 6a 00 00 e1 a9-00 00 bb 00 fc 6a 00 00 ...j.........j..
#100000010 01 aa 00 00 bb 00 fc 6a-00 00 21 aa 00 00 bb 00 .......j..!.....
#100000020 fc 6a 00 00 41 aa 00 00-bb 00 fc 6a 00 00 61 aa .j..A......j..a.
#100000030 00 00 bb 00 fc 6a 00 00-81 aa 00 00 bb 00 fc 6a .....j.........j
#100000040 00 00 a1 aa 00 00 bb 00-fc 6a 00 00 c1 aa 00 00 .........j......
#100000050 bb 00 fc 6a 00 00 e1 aa-00 00 bb 00 fc 6a 00 00 ...j.........j..
#100000060 01 ab 00 00 bb 00 fc 6a-00 00 21 ab 00 00 bb 00 .......j..!.....
then I tried "!u FFFFFFF0" which returns:
Op:
Dest:
Dest: 0
Src:
Srct: 0
it is just two nops and a jump if you mean you need to disassemble it as 16 bit
use ur
i patched the first 16 bytes from your query and disassemble it as 16 bit for demo below
0:000> db . l10
772805a6 90 90 e9 83 e8 00 00 00-fc 00 00 00 00 00 e1 ff ................
0:000> ur . l3
ntdll!LdrpDoDebuggerBreak+0x2c:
772805a6 90 nop
772805a7 90 nop
772805a8 e983e8 jmp EE2E
0:000>
Local Kernel Debugging is not Live it is Dead Debugging it operates on a snap shot
livekd operates on a state as the system was when dumped
!u is undocumented iirc and doesn't disassemble it provides a verbose details of a single instruction
0:000> u .+1 l1
ntdll!LdrpDoDebuggerBreak+0x2d:
772805a7 8975fc mov dword ptr [ebp-4],esi
0:000> !u 772805a7
Op: mov
Dest: esi
Dest: fffffffe
Src: dword ptr [ebp-4]
Srct: 0
0:000>
if you are looking for disassembling something like bios code use up
unassemble physical
kd> up cs:7c00 l1
0008:00007c00 eb52 jmp 00007c54
kd> up cs:7c54 l20
0008:00007c54 fa cli
0008:00007c55 33c0 xor eax,eax
0008:00007c57 8ed0 mov ss,ax
0008:00007c59 bc007cfb68 mov esp,68FB7C00h
0008:00007c5e c0071f rol byte ptr [edi],1Fh
0008:00007c61 1e push ds
0008:00007c62 686600cb88 push 88CB0066h
0008:00007c67 16 push ss
0008:00007c68 0e push cs
0008:00007c69 006681 add byte ptr [esi-7Fh],ah
0008:00007c6c 3e0300 add eax,dword ptr ds:[eax]
0008:00007c6f 4e dec esi
0008:00007c70 54 push esp
0008:00007c71 46 inc esi
0008:00007c72 53 push ebx
0008:00007c73 7515 jne 00007c8a
0008:00007c75 b441 mov ah,41h
0008:00007c77 bbaa55cd13 mov ebx,13CD55AAh
0008:00007c7c 720c jb 00007c8a
0008:00007c7e 81fb55aa7506 cmp ebx,675AA55h
0008:00007c84 f7c101007503 test ecx,3750001h
0008:00007c8a e9dd001e83 jmp 831e7d6c
i dont think debug.com is shipped in windows 10 x64 if you can get yourhands on win732bit etc you can use debug to disassemble the address
:>debug
-u f000:fff0 l1
F000:FFF0 EA5BE000F0 JMP F000:E05B
-u f000:e05b l1
F000:E05B EA3D3A00F0 JMP F000:3A3D
-u f000:3a3d l1
F000:3A3D FA CLI
-u f000:3a3d
F000:3A3D FA CLI
F000:3A3E B800F0 MOV AX,F000
F000:3A41 8ED0 MOV SS,AX
F000:3A43 BC493A MOV SP,3A49
F000:3A46 E93A8E JMP C883
F000:3A49 4B DEC BX
F000:3A4A 3ABB1DF1 CMP BH,[BP+DI+F11D]
F000:3A4E 2E CS:
F000:3A4F F747020800 TEST WORD PTR [BX+02],0008
F000:3A54 740E JZ 3A64
F000:3A56 32C0 XOR AL,AL
F000:3A58 BC5E3A MOV SP,3A5E
F000:3A5B E9E50B JMP 4643
-
I don't think you can step or disassemble the Physical Address f000:ffff in windbg.
I don't think it is mapped at all
I saw your post !db showing output so I wasn't quiet sure if it is available in x64.
afaik these codes are executed in Real Mode and you cant access them in protected mode with a software debugger like windbg
anyway back to the point
if you want to step through reset vector to MBR use a hardware emulator like bochs.
install bochs (2.6.11 x64 latest at the time of this edit) with the dlx demo
if you installed bochs in windows 10 you may need to give permissions to the bochs folder
(right click bochs folder->properties->security->edit full or write as the case may be)
once permission is granted you can double click the run.bat and you should land on LILo boot prompt
if you are here then close the bochs
open an elevated cmd prompt
and execute ../bochsdbg -f bochsrc
it will stop on Reset Vector
C:\Program Files\Bochs-2.6.11\dlxlinux>..\bochsdbg.exe -f ./bochsrc.bxrc
========================================================================
Bochs x86 Emulator 2.6.11
Built from SVN snapshot on January 5, 2020
Timestamp: Sun Jan 5 08:36:00 CET 2020
========================================================================
00000000000i[ ] reading configuration from ./bochsrc.bxrc
00000000000i[ ] installing win32 module as the Bochs GUI
00000000000i[ ] using log file bochsout.txt
Next at t=0
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
set a breakpoint at 0x7c00 using lb 0x7c00 (MBR START)
use s or n to step through
if you single step using s you may need to press s or ENTER 42.5 million times to reach MBR
here is a step through from reset vector to MBR using n or next
<bochs:5> blist
Num Type Disp Enb Address
1 lbreakpoint keep y 0x0000000000007c00
<bochs:6> u
00000000fffffff0: ( ): jmpf 0xf000:e05b ; ea5be000f0
<bochs:7> n
Next at t=1
(0) [0x0000000fe05b] f000:e05b (unk. ctxt): xor ax, ax ; 31c0
<bochs:8>
Next at t=2
(0) [0x0000000fe05d] f000:e05d (unk. ctxt): out 0x0d, al ; e60d
<bochs:9>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cut off
Next at t=32
(0) [0x0000000fe0c4] f000:e0c4 (unk. ctxt): rep stosw word ptr es:[di], ax ; f3ab
<bochs:39>
Next at t=160
(0) [0x0000000fe0c6] f000:e0c6 (unk. ctxt): call .+13763 (0x000f168c) ; e8c335
<bochs:40>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cut off
Next at t=5078
(0) [0x0000000fe0cf] f000:e0cf (unk. ctxt): mov word ptr ds:0x0413, ax ; a31304
<bochs:43>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cut off
Next at t=330285
(0) [0x0000000fe1f5] f000:e1f5 (unk. ctxt): call .-18344 (0x000f9a50) ; e858b8
<bochs:146>
Next at t=1403926
(0) [0x0000000fe1f8] f000:e1f8 (unk. ctxt): mov cx, 0xc000 ; b900c0
<bochs:147>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cut off
Next at t=1877324
(0) [0x0000000fe21e] f000:e21e (unk. ctxt): call .+14565 (0x000f1b06) ; e8e538
<bochs:161>
Next at t=5333736
(0) [0x0000000fe221] f000:e221 (unk. ctxt): call .+21186 (0x000f34e6) ; e8c252
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cut off
(0) [0x0000000fe230] f000:e230 (unk. ctxt): call .+12532 (0x000f1327) ; e8f430
<bochs:167>
Next at t=42311959
(0) [0x0000000fe233] f000:e233 (unk. ctxt): sti ; fb
<bochs:168>
Next at t=42311960
(0) [0x0000000fe234] f000:e234 (unk. ctxt): int 0x19 ; cd19
<bochs:169>
(0) Breakpoint 1, 0x0000000000007c00 in ?? () <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Next at t=42409977 <<<<< 42.5 million instructions until MBR is reached
(0) [0x000000007c00] 0000:7c00 (unk. ctxt): cli ; fa
<bochs:170> q
(0).[42409977] [0x000000007c00] 0000:7c00 (unk. ctxt): cli ; fa
Bochs is exiting. Press ENTER when you're ready to close this window.
I'm trying to do some remote hypervisor kernel debugging in WinDBG (latest version: 10.0.15063.468). The connection is established through the local network, everything works fine, I can break and display the stack or memory, but for some odd reason the search command doesn't work with the simplest stuff:
kd> db 0xfffff80002458350 L20
fffff800`02458350 00 00 00 00 40 00 00 42-2e 72 65 6c 6f 63 00 00 ....#..B.reloc..
fffff800`02458360 0c 06 00 00 00 00 40 01-00 08 00 00 00 a0 10 00 ......#.........
kd> s -sa 0xfffff80002458350 L20
fffff800`02458357 "B.reloc"
kd> s -b 0xfffff80002458350 L20 0x6c
kd> s -b 0xfffff80002458350 L20 0x72
kd> s -b 0xfffff80002458350 L100 0x72
kd> s -a 0xfffff80002458350 L100 "reloc"
kd> db 0xfffff80002458350 L20
fffff800`02458350 00 00 00 00 40 00 00 42-2e 72 65 6c 6f 63 00 00 ....#..B.reloc..
fffff800`02458360 0c 06 00 00 00 00 40 01-00 08 00 00 00 a0 10 00 ......#.........
kd> s -b 0xfffff80002458350 L100 'r'
kd> s -b 0xfffff80002458350 L100 'B'
Why would "-sa" work and "-b" not - what is this magic? Can anyone explain, or at least point me at how I could find the reason for this bizarre behavior?
I'm trying to compile my code into raw binary and as suggested by other SO posts (like this and this) I tried objdump:
$ gcc -c foo.c
$ objcopy -O binary foo.o foo.bin
Then I tried to make sure if this is valid:
$ objdump -d foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 89 7d fc mov %edi,-0x4(%rbp)
b: 48 89 75 f0 mov %rsi,-0x10(%rbp)
f: bf 00 00 00 00 mov $0x0,%edi
14: b8 00 00 00 00 mov $0x0,%eax
19: e8 00 00 00 00 callq 1e <main+0x1e>
1e: b8 00 00 00 00 mov $0x0,%eax
23: c9 leaveq
24: c3 ret
$ hexdump -C foo.bin
00000000 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 |.........zR..x..|
00000010 1b 0c 07 08 90 01 00 00 1c 00 00 00 1c 00 00 00 |................|
00000020 00 00 00 00 25 00 00 00 00 41 0e 10 86 02 43 0d |....%....A....C.|
00000030 06 60 0c 07 08 00 00 00 |.`......|
00000038
Evidently something is wrong. I checked this with the results of a gcc cross-compilation, with much the same obviously incorrect results.
You can pass -j .text to objcopy.
Can someone explain to me why appending to an array works when you do this:
func (s *Sample) Append(name string) {
d := &Stuff{
name: name,
}
s.data = append(s.data, d)
}
Full code here
But not when you do this:
func (s Sample) Append(name string) {
d := &Stuff{
name: name,
}
s.data = append(s.data, d)
}
Is there any reason at all why you would want to use the second example.
As mentioned in the FAQ
Should I define methods on values or pointers?
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
First, and most important, does the method need to modify the receiver? If it does, the receiver must be a pointer. (Slices and maps act as references, so their story is a little more subtle, but for instance to change the length of a slice in a method the receiver must still be a pointer.)
In the examples above, if pointerMethod modifies the fields of s, the caller will see those changes, but valueMethod is called with a copy of the caller's argument (that's the definition of passing a value), so changes it makes will be invisible to the caller.
In your case, func (s Sample) Append(name string) modifies a copy.
laher reminds us in the comments that using a value instead of pointer also means getting a copy, and respecting the immutable nature of an object::
You'd want to use the non-pointer valueMethod when (for nstance) you're returning a [value derived from an] 'immutable' private property.
See "Why are receivers pass by value in Go?":
Can be useful if for instance you have a small immutable object. The caller can know for certain that this method doesn't modify it's receiver.
They can't know this if the receiver is a pointer without reading the code first.
Go slices are a tricky beast. Internally, a variable of slice type (like []int) looks like this:
struct {
data *int // pointer to the data area
len int
cap int
}
When you pass a slice to a function, this structure is passed by value, while the underlying data area (i.e. what data points to) is not copied. The builtin append() function modifies the data area (or generates a new one) and returns a new slice with updated len, data, and cap values. If you want to overwrite anything that is not part of the underlying data area, you need to pass a pointer to the slice or return a modified slice.
Go passes arguments by value, not by reference, unless you use a pointer. So inside the function, you're not modifying s in any outer scope if you simply pass by value. However, when you pass a pointer, you're able to modify the "real" variable rather than just the copy that exists inside the function.
While most of the answers here capture exactly what happens, I wanted to dig a bit into how/why that's happening. I started with a couple small snippets of code:
pointer method
package main
import "fmt"
type Bar struct{}
func (b *Bar) Print() {
fmt.Println("debosmit ray")
}
func main() {
b := Bar{}
b.Print()
}
value method
package main
import "fmt"
type Bar struct{}
func (b Bar) Print() {
fmt.Println("debosmit ray")
}
func main() {
b := Bar{}
b.Print()
}
Then, I wanted to look at the assembly for just the files (generated using go tool compile -S filename.go > filename.S, for each of the files. Both the outputs are available here (should be available forever).
Let's take a look at the output of diff pointer.S value.S (pointer -> has pointer method, value -> has value method).
14,15c14,15
< "".(*Bar).Print STEXT size=138 args=0x8 locals=0x58
< 0x0000 00000 (bar.go:7) TEXT "".(*Bar).Print(SB), ABIInternal, $88-8
---
> "".Bar.Print STEXT size=138 args=0x0 locals=0x58
> 0x0000 00000 (bar.go:7) TEXT "".Bar.Print(SB), ABIInternal, $88-0
24c24
< 0x001d 00029 (bar.go:7) FUNCDATA $0, gclocals·2a5305abe05176240e61b8620e19a815(SB)
---
> 0x001d 00029 (bar.go:7) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
26c26
< 0x001d 00029 (bar.go:7) FUNCDATA $3, "".(*Bar).Print.stkobj(SB)
---
> 0x001d 00029 (bar.go:7) FUNCDATA $3, "".Bar.Print.stkobj(SB)
126a127,200
> "".(*Bar).Print STEXT dupok size=187 args=0x8 locals=0x58
> 0x0000 00000 (<autogenerated>:1) TEXT "".(*Bar).Print(SB), DUPOK|WRAPPER|ABIInternal, $88-8
> 0x0000 00000 (<autogenerated>:1) MOVQ (TLS), CX
> 0x0009 00009 (<autogenerated>:1) CMPQ SP, 16(CX)
> 0x000d 00013 (<autogenerated>:1) PCDATA $0, $-2
> 0x000d 00013 (<autogenerated>:1) JLS 154
> 0x0013 00019 (<autogenerated>:1) PCDATA $0, $-1
> 0x0013 00019 (<autogenerated>:1) SUBQ $88, SP
> 0x0017 00023 (<autogenerated>:1) MOVQ BP, 80(SP)
> 0x001c 00028 (<autogenerated>:1) LEAQ 80(SP), BP
> 0x0021 00033 (<autogenerated>:1) MOVQ 32(CX), BX
> 0x0025 00037 (<autogenerated>:1) TESTQ BX, BX
> 0x0028 00040 (<autogenerated>:1) JNE 165
> 0x002a 00042 (<autogenerated>:1) NOP
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $1, gclocals·2589ca35330fc0fce83503f4569854a0(SB)
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $3, "".(*Bar).Print.stkobj(SB)
> 0x002a 00042 (<autogenerated>:1) CMPQ ""..this+96(SP), $0
> 0x0030 00048 (<autogenerated>:1) JEQ 148
> 0x0032 00050 (<unknown line number>) NOP
> 0x0032 00050 (bar.go:8) XORPS X0, X0
> 0x0035 00053 (bar.go:8) MOVUPS X0, ""..autotmp_13+64(SP)
> 0x003a 00058 (bar.go:8) LEAQ type.string(SB), AX
> 0x0041 00065 (bar.go:8) MOVQ AX, ""..autotmp_13+64(SP)
> 0x0046 00070 (bar.go:8) LEAQ ""..stmp_2(SB), AX
> 0x004d 00077 (bar.go:8) MOVQ AX, ""..autotmp_13+72(SP)
> 0x0052 00082 (<unknown line number>) NOP
> 0x0052 00082 ($GOROOT/src/fmt/print.go:274) MOVQ os.Stdout(SB), AX
> 0x0059 00089 ($GOROOT/src/fmt/print.go:274) LEAQ go.itab.*os.File,io.Writer(SB), CX
> 0x0060 00096 ($GOROOT/src/fmt/print.go:274) MOVQ CX, (SP)
> 0x0064 00100 ($GOROOT/src/fmt/print.go:274) MOVQ AX, 8(SP)
> 0x0069 00105 ($GOROOT/src/fmt/print.go:274) LEAQ ""..autotmp_13+64(SP), AX
> 0x006e 00110 ($GOROOT/src/fmt/print.go:274) MOVQ AX, 16(SP)
> 0x0073 00115 ($GOROOT/src/fmt/print.go:274) MOVQ $1, 24(SP)
> 0x007c 00124 ($GOROOT/src/fmt/print.go:274) MOVQ $1, 32(SP)
> 0x0085 00133 ($GOROOT/src/fmt/print.go:274) PCDATA $1, $1
> 0x0085 00133 ($GOROOT/src/fmt/print.go:274) CALL fmt.Fprintln(SB)
> 0x008a 00138 (bar.go:8) MOVQ 80(SP), BP
> 0x008f 00143 (bar.go:8) ADDQ $88, SP
> 0x0093 00147 (bar.go:8) RET
> 0x0094 00148 (<autogenerated>:1) CALL runtime.panicwrap(SB)
> 0x0099 00153 (<autogenerated>:1) XCHGL AX, AX
> 0x009a 00154 (<autogenerated>:1) NOP
> 0x009a 00154 (<autogenerated>:1) PCDATA $1, $-1
> 0x009a 00154 (<autogenerated>:1) PCDATA $0, $-2
> 0x009a 00154 (<autogenerated>:1) CALL runtime.morestack_noctxt(SB)
> 0x009f 00159 (<autogenerated>:1) PCDATA $0, $-1
> 0x009f 00159 (<autogenerated>:1) NOP
> 0x00a0 00160 (<autogenerated>:1) JMP 0
> 0x00a5 00165 (<autogenerated>:1) LEAQ 96(SP), DI
> 0x00aa 00170 (<autogenerated>:1) CMPQ (BX), DI
> 0x00ad 00173 (<autogenerated>:1) JNE 42
> 0x00b3 00179 (<autogenerated>:1) MOVQ SP, (BX)
> 0x00b6 00182 (<autogenerated>:1) JMP 42
> 0x0000 65 48 8b 0c 25 00 00 00 00 48 3b 61 10 0f 86 87 eH..%....H;a....
> 0x0010 00 00 00 48 83 ec 58 48 89 6c 24 50 48 8d 6c 24 ...H..XH.l$PH.l$
> 0x0020 50 48 8b 59 20 48 85 db 75 7b 48 83 7c 24 60 00 PH.Y H..u{H.|$`.
> 0x0030 74 62 0f 57 c0 0f 11 44 24 40 48 8d 05 00 00 00 tb.W...D$#H.....
> 0x0040 00 48 89 44 24 40 48 8d 05 00 00 00 00 48 89 44 .H.D$#H......H.D
> 0x0050 24 48 48 8b 05 00 00 00 00 48 8d 0d 00 00 00 00 $HH......H......
> 0x0060 48 89 0c 24 48 89 44 24 08 48 8d 44 24 40 48 89 H..$H.D$.H.D$#H.
> 0x0070 44 24 10 48 c7 44 24 18 01 00 00 00 48 c7 44 24 D$.H.D$.....H.D$
> 0x0080 20 01 00 00 00 e8 00 00 00 00 48 8b 6c 24 50 48 .........H.l$PH
> 0x0090 83 c4 58 c3 e8 00 00 00 00 90 e8 00 00 00 00 90 ..X.............
> 0x00a0 e9 5b ff ff ff 48 8d 7c 24 60 48 39 3b 0f 85 77 .[...H.|$`H9;..w
> 0x00b0 ff ff ff 48 89 23 e9 6f ff ff ff ...H.#.o...
> rel 5+4 t=17 TLS+0
> rel 61+4 t=16 type.string+0
> rel 73+4 t=16 ""..stmp_2+0
> rel 85+4 t=16 os.Stdout+0
> rel 92+4 t=16 go.itab.*os.File,io.Writer+0
> rel 134+4 t=8 fmt.Fprintln+0
> rel 149+4 t=8 runtime.panicwrap+0
> rel 155+4 t=8 runtime.morestack_noctxt+0
139,143c213,217
< go.info."".(*Bar).Print$abstract SDWARFINFO dupok size=26
< 0x0000 04 2e 28 2a 42 61 72 29 2e 50 72 69 6e 74 00 01 ..(*Bar).Print..
< 0x0010 01 11 62 00 00 00 00 00 00 00 ..b.......
< rel 0+0 t=24 type.*"".Bar+0
< rel 21+4 t=29 go.info.*"".Bar+0
---
> go.info."".Bar.Print$abstract SDWARFINFO dupok size=23
> 0x0000 04 2e 42 61 72 2e 50 72 69 6e 74 00 01 01 11 62 ..Bar.Print....b
> 0x0010 00 00 00 00 00 00 00 .......
> rel 0+0 t=24 type."".Bar+0
> rel 18+4 t=29 go.info."".Bar+0
297c371,392
< type."".Bar SRODATA size=96
---
> type..namedata.*func(main.Bar)- SRODATA dupok size=18
> 0x0000 00 00 0f 2a 66 75 6e 63 28 6d 61 69 6e 2e 42 61 ...*func(main.Ba
> 0x0010 72 29 r)
> type.*func("".Bar) SRODATA dupok size=56
> 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
> 0x0010 7f 95 9a 2f 08 08 08 36 00 00 00 00 00 00 00 00 .../...6........
> 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 0x0030 00 00 00 00 00 00 00 00 ........
> rel 24+8 t=1 runtime.memequal64·f+0
> rel 32+8 t=1 runtime.gcbits.01+0
> rel 40+4 t=5 type..namedata.*func(main.Bar)-+0
> rel 48+8 t=1 type.func("".Bar)+0
> type.func("".Bar) SRODATA dupok size=64
> 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
> 0x0010 b4 2e bc 27 02 08 08 33 00 00 00 00 00 00 00 00 ...'...3........
> 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 0x0030 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> rel 32+8 t=1 runtime.gcbits.01+0
> rel 40+4 t=5 type..namedata.*func(main.Bar)-+0
> rel 44+4 t=6 type.*func("".Bar)+0
> rel 56+8 t=1 type."".Bar+0
> type."".Bar SRODATA size=112
303c398,399
< 0x0050 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
---
> 0x0050 00 00 00 00 01 00 01 00 10 00 00 00 00 00 00 00 ................
> 0x0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
309a406,409
> rel 96+4 t=5 type..namedata.Print.+0
> rel 100+4 t=25 type.func()+0
> rel 104+4 t=25 "".(*Bar).Print+0
> rel 108+4 t=25 "".Bar.Print+0
320a421,423
> ""..stmp_2 SRODATA size=16
> 0x0000 00 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 ................
> rel 0+8 t=1 go.string."debosmit ray"+0
325,326c428,429
< gclocals·2a5305abe05176240e61b8620e19a815 SRODATA dupok size=9
< 0x0000 01 00 00 00 01 00 00 00 00 .........
---
> gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
> 0x0000 01 00 00 00 00 00 00 00 ........
329c432
< "".(*Bar).Print.stkobj SRODATA size=24
---
> "".Bar.Print.stkobj SRODATA size=24
333,334d435
< gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
< 0x0000 01 00 00 00 00 00 00 00 ........
338a440,447
> gclocals·1a65e721a2ccc325b382662e7ffee780 SRODATA dupok size=10
> 0x0000 02 00 00 00 01 00 00 00 01 00 ..........
> gclocals·2589ca35330fc0fce83503f4569854a0 SRODATA dupok size=10
> 0x0000 02 00 00 00 02 00 00 00 00 00 ..........
> "".(*Bar).Print.stkobj SRODATA dupok size=24
> 0x0000 01 00 00 00 00 00 00 00 f0 ff ff ff ff ff ff ff ................
> 0x0010 00 00 00 00 00 00 00 00 ........
> rel 16+8 t=1 type.[1]interface {}+0
Here, it is evident that for the value method case:
a copy of b was created due to the b.Print() invocation
a copy of the string rel 0+8 t=1 go.string."debosmit ray"+0 was set on the copied struct.
Therefore, this further concretizes that when you use value pointers:
a copy of the object is made when you invoke methods on that object
any mutations to internal state, will only reflect on that copy of the object