{"id":13576055,"url":"https://github.com/repnz/windbg-cheat-sheet","last_synced_at":"2025-04-05T05:30:35.231Z","repository":{"id":39492131,"uuid":"197926844","full_name":"repnz/windbg-cheat-sheet","owner":"repnz","description":"My personal cheat sheet for using WinDbg for kernel debugging","archived":false,"fork":false,"pushed_at":"2024-10-11T22:49:09.000Z","size":266,"stargazers_count":381,"open_issues_count":0,"forks_count":59,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-05T12:32:56.985Z","etag":null,"topics":["cheat-sheet","cheatsheet","debugging","guide","kernel","windbg"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/repnz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-20T12:24:21.000Z","updated_at":"2024-10-31T02:15:04.000Z","dependencies_parsed_at":"2024-11-05T12:31:04.064Z","dependency_job_id":"473f87bd-b2a6-475c-9f53-921e8b76e1c0","html_url":"https://github.com/repnz/windbg-cheat-sheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/repnz%2Fwindbg-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/repnz%2Fwindbg-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/repnz%2Fwindbg-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/repnz%2Fwindbg-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/repnz","download_url":"https://codeload.github.com/repnz/windbg-cheat-sheet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294015,"owners_count":20915329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cheat-sheet","cheatsheet","debugging","guide","kernel","windbg"],"created_at":"2024-08-01T15:01:06.627Z","updated_at":"2025-04-05T05:30:34.530Z","avatar_url":"https://github.com/repnz.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","\u003ca id=\"8c5a692b5d26527ef346687e047c5c21\"\u003e\u003c/a\u003e收集"],"sub_categories":[],"readme":"# Kernel Debugging \u0026 WinDbg Cheat Sheet\n\nMy personal cheat sheet for using WinDbg for kernel debugging.\nThis cheat sheet / mini guide will be updated as I do new stuff with WinDbg.\n\n## Kernel Debugging Setup\n\n### Installing the debugging tools\n\n- To use windbg, you have to install the [Windows Debugging Tools](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/).\n- I recommend to install Windbg Preview from the Windows Store.\n\n### Setting a VM\n\nCreate a VM in Vmware Workstation and install Windows from ISO.\n\n### Disable Windows Defender\n\nWhen setting up a VM for debugging, it's useful to disable Windows Defender. It's recommended\nfor a couple of reasons:\n\n- To save resources in the VM\n- In case you want to execute malicious software, you don't want defender to prevent it's execution.\n\nFollow these steps:\n\n1. Turn it off from it's settings: Virus \u0026 Threat protection, Real-time protection, turn off.\nWindows defender will start again in case you reboot, so we need to perform additional steps.\n2. We can disable Windows Defender using gpedit.msc. In case your setup is Windows Home, gpedit\nis disabled, so you need to download and run [GPEdit Enabler](https://www.itechtics.com/?dl_id=43). Run as admin and make sure you have an internet connection.\n3. Run \"gpedit.msc\" -\u003e Computer Configuration \u003e Administrative Templates \u003e Windows Components \u003e Windows Defender -\u003e Turn Off Windows Defender -\u003e Enabled\n\n### Install VirtualKd\n\nVirtualKd enables you to debug a VM by connecting over a named pipe.\n\n- Download [VirtualKd Redux](https://github.com/4d61726b/VirtualKD-Redux/releases)\n- The redux version is a newer version that supports Vmware 15 and has a few bugfixes.\n- Extract VirtualKd in the host in any location you like (I like c:\\tools\\virtualkd)\n- Run the \"target\" executable inside the guest\n- Run vmmon64.exe / vmmon.exe on the host (According to the host's architecture)\n- Configure the path of Windbg / Windbg Preview in vmmon.\n- Make sure \"Start Debugger Automatically\" is not marked.\n\n### Configure VM for debugging\n\nRun the following commands in an admin command line.\n\n- ```bcdedit /set testsigning on```\n- ```bcdedit /debug on```\n- ```bcdedit /dbgsettings serial debugport:1 baudrate:115200```\n\n### Connecting to the debugger\n\nAfter these preparations, we can connect to the debugger by doing these steps:\n\n1. Restart VM. click F8 and choose \"Disable Device Signing Enforcement\" - that will allow your driver to be load.  \n2. At that point the VM will stuck. It will wait for the debugger to connect. Click \"Run Debugger\" in VMMON to connect\n\n### Configuring Windbg\n\nNow, the debugger should be connected to the VM. We need to setup some configurations in the\ndebugger:\n\n- Setup symbols server: There are 2 ways to setup symbols path:\n  - Environment Variable: This is the easier way I typically use. Set a new environment variable named _NT_SYMBOL_PATH with the\n    following value: ```srv*c:\\symbols\\sym*http://msdl.microsoft.com/download/symbols\"```\n  - You can also configure the symbols using a debugger command like this: ```.sympath srv*c:\\symbols\\sym*http://msdl.microsoft.com/download/symbols\"```\n\n- If the debugger crashes / closes, you can just open a new debugger by clicking the \"run debugger\" button\n- Arrange the windows / font however you like.\n\nIf you use the old Windbg, you should use \"Save Workspace\" after arranging the windows in the way you like, so next time you open WinDbg it will save this arrangement. It will also restore the symbol path.\n\n### Configuring DbgPrint output\n\nWhen debugging a driver, It's useful to be able to call [DbgPrintEx](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-dbgprintex) and see messages in the debugger\nwindow. By default, all DbgPrint calls are filtered out. There are 3 ways to enable debugger messages:\n\n1. In windbg, run ```ed nt!Kd_DEFAULT_MASK 0xF```. Kd_DEFAULT_MASK is a global variable inside \nntoskrnl that is checked before printing messages to the debugger. If you write 0xF to this variable it means you want to get all messages. You will need to do this every time the machine reboots.\n2. If you don't want to edit this variable every time the machine reboots, you can configure this\nvia registry. Run the following command (THIS REQUIRES A REBOOT.)\n\n```bat\nreg add \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Debug Print Filter\" /ve /t REG_DWORD /d 15\n```\n\nBecause we use the \"default mask\" here you'll start to see every DbgPrint from all drivers so it can become pretty noisy. The other option is to filter by ComponentId. When you call DbgPrintEx, the first argument is a component id. Instead of setting the Kd_DEFAULT_MASK variable, you can\nset a component-specific mask. For example:\n\n1. Make sure that when you call DbgPrintEx, you specify the ```DPFLTR_IHVDRIVER_ID``` component.\n2. Run the following command, to edit this component's mask:  ```ed nt!Kd_IHVDRIVER_Mask 0xf```\n3. You can do it in the registry too, run the following command:\n\n```bat\nreg add \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Debug Print Filter\" /v IHVDRIVER /t REG_DWORD /d 15\n``` \n\n## Initialization Commands\n\n- !sym noisy - this will allow you to understand better why the debugger is stuck:)\n- .kdfiles \u003cmap file\u003e - this will save you some time by automatically loading the .sys file from the host machine,\n\tthis way you won't need to copy the .sys file. The downside is that it doesn't work with user mode executables,\n\tso you need to find another method for them (copy pasting or using some kind of share)\n- .reload - this will referesh the symbols.\n\n\n## Installing and Loading Device Drivers\n\nInstalling a driver is done by registering it in the registry under the services key. Loading the driver is done by calling the \nNtLoadDriver syscall.\n\nYou can either:\n\n- Use [Osr Loader](https://www.osronline.com/article.cfm%5Earticle=157.htm) - This works on win 7-10\n- Use builtin SC tool (only win10)\n  - Use \"sc create \u003cREG_KEY_NAME\u003e type= kernel binPath= \u003cFULL_PATH\u003e\" to install the driver \n  - Use \"sc start \u003cREG_KEY_NAME\u003e\" to load the driver\n\nIf there the DriverEntry function returns an error status, it will be returned to \"sc\" / OsrLoader and the driver will be unloaded without\ncalling DriverUnload.\n\nTo debug your own driver, move it into the virtual machine and install it. Then you are welcome to put a breakpoint on the DriverEntry\nby using \"bu DriverName!DriverEntry\" and then start the driver. If you want to update the code (say you found a bug..) then you can \nstop the driver, recompile, move the files into the VM, and start the driver again. \n\n## General WinDbg\n\n- ```.\u003ccommand\u003e``` - run a command. This command is built-into the debugger\n- ```!\u003ccommand\u003e``` - run an extension. Some extensions arrive by default, like \"!process\"\n- Control-Break - Abort Long Running Operation / Debug Break\n\n## Exploring Modules And Symbols\n\nSymbols are important when examining modules. When examining a certain module we always need to verify it's symbols\nare loaded. We can use the ```lm``` command to see which modules are loaded right now - for each module we can see the\nstatus of the symbols. Basically information about loaded modules is not 'updated' unless ```.reload``` is used before.\nuse .reload when changing the process context or when you're missing a specific modules in the list.\n\n- ```.reload``` to reload symbols of loaded modules. Typically used to load symbols of modules that weren't loaded before\n- You may want to use \u003ccode\u003e!sym noisy\u003c/code\u003e to diagnose symbol loading errors.\n- ```.reload /u``` - unload symbols. This is used to release the .pdb file of compiled code.\n  - Sometimes it's needed to forcefully close handles to PDB files because WinDbg does not close them.\n  (using process explorer or process hacker..)\n- ```lm``` (List Modules): Prints list of loaded modules\n- ```x``` (Examine): Prints loaded symbols - ```x \u003cmodule_name\u003e!\u003csymbol_name\u003e``` - you can use wildcard on both sides\n    - Search for a function by name: ```x MyDllName!FunctionName```\n    - Search for a function with wildcards ```x MyDllName!*Func``` (ends with Func)\n\n## Source Navigation\n\n- ```.open -a \u003csymbol\u003e``` - open the source file with this symbol\n\t\n## Breakpoints\n\nThese are the commands for int3 breakpoints.\n- bp - normal breakpoint\n- Breakpoint On DriverEntry - If your driver is not loaded yet, you cannot use \"bp MyDriver!DriverEntry\" because this symbol\nis not known yet. You can use the \"bu\" command, this allows to put a breakpoint on the driver entry because those breakpoints are calculated when a driver is loaded. Another trick to break at the load of drivers (Useful in case you don't have symbols) is breaking\nin ntoskrnl.exe where DriverEntry is called. (For example, IopLoadDriver)\n- ```bl``` - list breakpoints\n- ```bc *``` / ```bc \u003cbreakpoint_id\u003e``` - clear breakpoint\n- ```bp /1 \u003clocation\u003e``` - temporary breakpoint (break 1 time..)\n- Breaking on source lines - \n\t- You can use F9 while placing the cursor on a specific line of code.\n\t- Old Method: Find the source line using the status bar and run \u003ccode\u003ebp `\u003csourcefile\u003e:\u003cline\u003e`\u003c/code\u003e\n\t- Sometimes this method is too slow because it cannot know which module you are trying to break on, so it'll\n\tstart downloading symbols of other modules....\n\t- ```bp `module_name!file.cpp:206` ``` is better - specifies the name of the module\n\n- ```bp /p \u003cEPROCESS address\u003e \u003cbreakpoint address\u003e``` - Break on a specific process - \n\tsay you want your breakpoint to be on only for a specific process, you can use /p to do it\n  \n- ```bp /t \u003cETHREAD address\u003e \u003cbreakpoint address\u003e``` - same as above, for threads.\n\n- ```bp \u003coptions\u003e \"\u003ccommand\"\u003e``` - this will run a windbg command after breaking. You can combine multipile commands using ';' for example:\n\nThis command will break at line 385 in the ProcessProtector.c file in the ProcessProtector module and it will print \nbasic process information, a stack trace, and it will continue on.\nLimit the number of times the breakpoint hits to prevent floods:\n\n```\nbp /5 `ProcessProtector!ProcessProtector.c:385` \"!process -1 0; k; g\"\n```\n\nBreak right before the process entry point in kernel debugging:\n```\nbp ntdll!LdrpInitializeProcess \"bp /1 KERNEL32!BaseThreadInitThunk; g\"\n```\n\n### Conditional breakpoints\n\nConditional breakpoints allows you to break if a some DX expression evaluates to true.\n\n## Analyzing BugChecks\n\n- \u003ccode\u003eanalyze -v\u003c/code\u003e: Shows detailed information about the exception\n\n## Tracing and Stepping\n\n- (F5) ```g``` : (go) continue\n- (F10) : step over\n- (F11) : step into\n- ```tt``` - Trace until next return\n\n## Analyzing Program State\n\n- Use memory window to see raw memory\n- use \"dt\" to see observe data structures\n- use \"dx\" to evaluate C++ Expressions\n- ```k``` - stack trace\n- ```!stacks``` - Inspect the stacks of all of the running threads.\n    - ```!stacks 1 \u003cfilter_string\u003e``` can be used to filter based on some string in the stack\n\n#### Function arguments\n\nWhen debugging, it's useful to see the function arguments.\n\nThe first 4 arguments are in: rcx, rdx, r8, r9. Also, the caller allocates a shadow space for them, but the caller does not \nstore the arguments in this space (it's reserved for the callee)\n\n\n```\nkd\u003e dq /c1 rsp\nfffffd08`ee125dc8  fffff801`71222935 --\u003e the return address. only relevant inside the function\nfffffd08`ee125dd0  00000025`196fdb50 --\u003e arg1 shadow\nfffffd08`ee125dd8  00000000`00000000 --\u003e arg2 shadow\nfffffd08`ee125de0  00000000`00000000 --\u003e arg3 shadow\nfffffd08`ee125de8  00000000`00000000 --\u003e arg4 shadow\nfffffd08`ee125df0  00007fff`00000002 --\u003e arg5\nfffffd08`ee125df8  00000025`196fda48 --\u003e arg6\nfffffd08`ee125e00  ffffb484`5254e080 --\u003e arg7\nfffffd08`ee125e08  fffff801`71449ebf --\u003e ar8\nfffffd08`ee125e10  00000000`00000000 --\u003e....\nfffffd08`ee125e18  00000000`00000000\n```\n\n\nIt's also useful to be able to extract function arguments of previous calls in the callstack. In 32 bit, windbg supports reading function\narguments from the stack using the 'kv' command. Say we are debugging this code:\n\n```C\n#include \u003cstdio.h\u003e\n\ntypedef struct OBJ {\n    int a;\n    int b;\n    int c;\n} OBJ, *POBJ;\n\nint AddValues1(int a, int b)\n{\n    return a + b;\n}\n\nint AddValues2(int a, int b)\n{\n    return AddValues1(a, b);\n}\n\nOBJ AddObjects(POBJ Obj1, POBJ Obj2)\n{\n    OBJ Obj3 = { 0 };\n    Obj3.a = AddValues2(Obj1-\u003ea, Obj2-\u003ea);\n    return Obj3;\n}\n\nint main()\n{\n    OBJ Obj1 = { 0 };\n    OBJ Obj2 = { 0 };\n\n    Obj1.a = 1;\n    Obj1.b = 2;\n    Obj1.c = 3;\n    Obj2.a = 4;\n    Obj2.b = 5;\n    Obj2.c = 6;\n\n    printf(\"Obj1 Address: 0x%p\\n\", \u0026Obj1);\n    printf(\"Obj2 Address: 0x%p\\n\", \u0026Obj2);\n\n    AddObjects(\u0026Obj1, \u0026Obj2);\n\n    return 0;\n}\n```\n\nThe following example will show how to extract the 32 bit arguments:\n\n```\n0:000\u003e bp AddValues1\n0:000\u003e g\nBreakpoint 0 hit\neax=00000004 ebx=01059000 ecx=00000001 edx=00000001 esi=00891a40 edi=0133fc58\neip=008910c0 esp=0133fb80 ebp=0133fc58 iopl=0         nv up ei pl zr na pe nc\ncs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246\nProject1!AddValues1:\n008910c0 55              push    ebp\n0:000\u003e kv\n # ChildEBP RetAddr  Args to Child              \n00 0133fb7c 00891145 00000001 00000004 0133fd4c Project1!AddValues1 (FPO: [Non-Fpo]) (CONV: cdecl)\n01 0133fc58 0089104e 00000001 00000004 0133fe80 Project1!AddValues2+0x35 (FPO: [Non-Fpo]) (CONV: cdecl)\n02 0133fd4c 008912d8 0133fd70 0133fe6c 0133fe58 Project1!AddObjects+0x4e (FPO: [Non-Fpo]) (CONV: cdecl)\n03 0133fe80 008919e3 00000001 015f5db8 015fb990 Project1!main+0xa8 (FPO: [Non-Fpo]) (CONV: cdecl)\n04 0133fea0 008918b7 fdf471b3 00891a40 00891a40 Project1!invoke_main+0x33 (FPO: [Non-Fpo]) (CONV: cdecl)\n05 0133fefc 0089175d 0133ff0c 00891a48 0133ff1c Project1!__scrt_common_main_seh+0x157 (FPO: [Non-Fpo]) (CONV: cdecl) [d:\\agent\\_work\\3\\s\\src\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl @ 288] \n06 0133ff04 00891a48 0133ff1c 768f6359 01059000 Project1!__scrt_common_main+0xd (FPO: [Non-Fpo]) (CONV: cdecl) [d:\\agent\\_work\\3\\s\\src\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl @ 331] \n07 0133ff0c 768f6359 01059000 768f6340 0133ff78 Project1!mainCRTStartup+0x8 (FPO: [Non-Fpo]) (CONV: cdecl) [d:\\agent\\_work\\3\\s\\src\\vctools\\crt\\vcstartup\\src\\startup\\exe_main.cpp @ 17] \n08 0133ff1c 77738964 01059000 5f9cd80a 00000000 KERNEL32!BaseThreadInitThunk+0x19 (FPO: [Non-Fpo])\n09 0133ff78 77738934 ffffffff 7775a0de 00000000 ntdll!__RtlUserThreadStart+0x2f (FPO: [SEH])\n0a 0133ff88 00000000 00891a40 01059000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])\n0:000\u003e dx (OBJ*)0x0133fd70 \u003c\u003c\u003c\u003c\u003c\u003c This is the \"hidden\" return value argument, as expected it has garbage\n(OBJ*)0x0133fd70                 : 0x133fd70 [Type: OBJ *]\n    [+0x000] a                : -858993460 [Type: int]\n    [+0x004] b                : -858993460 [Type: int]\n    [+0x008] c                : -858993460 [Type: int]\n0:000\u003e dx (OBJ*)0x0133fe6c  \u003c\u003c\u003c\u003c\u003c\u003c This is arg1 from the call to AddObjects\n(OBJ*)0x0133fe6c                  : 0x133fe6c [Type: OBJ *]\n    [+0x000] a                : 1 [Type: int]\n    [+0x004] b                : 2 [Type: int]\n    [+0x008] c                : 3 [Type: int]\n0:000\u003e dx (OBJ*)0x0133fe58  \u003c\u003c\u003c\u003c\u003c\u003c This is arg2\n(OBJ*)0x0133fe58                   : 0x133fe58 [Type: OBJ *]\n    [+0x000] a                : 4 [Type: int]\n    [+0x004] b                : 5 [Type: int]\n    [+0x008] c                : 6 [Type: int]\n\n```\n\nIn 64 bit things are a bit more complicated because the calling conventions do not pass the 4 first arguments on the stack, but on registers.\nThe KV command still tries to read the arguments from the stack, from the shadow space of passed arguments. So, if the file is compiled\nin debug mode, it can have valid arguments when using KV. In case the arguments are not saved in the shadow space, we can still try to extract\nthem by tracing the flow of register usage and seeing whether the value is saved in the stack somewhere. In some cases the parameter is lost because\nit's not saved anywhere on the stack. If we are lucky the parameter is saved somewhere and we can read it.\n\nThe way I typically do this is to disassemble the function from the callstack, and see if the arguments are saved in the shadow space. If they are I use\nthe KV command to extract the arguments, or use the Child SP value with ```dq /c1 @rsp```\n\n\n\n## Locks\n\nInspecting the usage of locks is typically useful when debugging deadlock\n\n- !cs: (\"Critical Sections\")\n\n## Processes\n\n- cid - CID in the windows structures means client id. Most of the time it refers to a ProcessId or a ThreadId but \nsometimes it's both in the same struct. (The struct CLIENT_ID contains UniqueProcessId and UniqueThreadId)\n\n### Current Process\n\n- \u003ccode\u003e!process\u003c/code\u003e - Dump current process information\n```\nkd\u003e !process\nPROCESS ffff8906293a1080\n    SessionId: 1  Cid: 0f3c    Peb: 2063b93000  ParentCid: 122c\n    DirBase: 72810002  ObjectTable: ffffb088f57cedc0  HandleCount:  33.\n    Image: WindowsInspector.Controller.exe\n    VadRoot ffff89062992fac0 Vads 22 Clone 0 Private 354. Modified 0. Locked 0.\n    DeviceMap ffffb088f43ed730\n    Token                             ffffb088f745d060\n    ElapsedTime                       00:00:00.233\n    UserTime                          00:00:00.000\n    KernelTime                        00:00:00.000\n    QuotaPoolUsage[PagedPool]         24560\n    QuotaPoolUsage[NonPagedPool]      3256\n    Working Set Sizes (now,min,max)  (847, 50, 345) (3388KB, 200KB, 1380KB)\n    PeakWorkingSetSize                814\n    VirtualSize                       4143 Mb\n    PeakVirtualSize                   4143 Mb\n    PageFaultCount                    849\n    MemoryPriority                    BACKGROUND\n    BasePriority                      8\n    CommitCharge                      540\n\n        THREAD ffff890628533080  Cid 0f3c.0de0  Teb: 0000002063b94000 Win32Thread: 0000000000000000 RUNNING on processor 0\n\n```\n\n\n### Listing processes\n\n```.tlist``` - \u003cprocess_id\u003e:\u003cprocess_name\u003e\n\n```\n0n17636 chrome.exe\n0n17744 chrome.exe\n0n13076 chrome.exe\n0n17148 chrome.exe\n0n17516 chrome.exe\n0n10776 chrome.exe\n0n13176 cmd.exe\n```\n\n```!process 0 0```\n\n```\n\nPROCESS ffff89062943c080\n    SessionId: 1  Cid: 09e0    Peb: 9780215000  ParentCid: 03ac\n    DirBase: 6ce90002  ObjectTable: ffffb088f57cad80  HandleCount: 309.\n    Image: RuntimeBroker.exe\n\nPROCESS ffff8906297ce080\n    SessionId: 1  Cid: 06f8    Peb: 3877758000  ParentCid: 122c\n    DirBase: 77800002  ObjectTable: ffffb088f3ac8880  HandleCount:  33.\n    Image: WindowsInspector.Controller.exe\n/\n```\n\n```!process 0 0 \u003cprocess_name\u003e```\n\n```\nkd\u003e !process 0 0 WindowsInspector.Controller.exe\nPROCESS ffff8906297ce080\n    SessionId: 1  Cid: 06f8    Peb: 3877758000  ParentCid: 122c\n    DirBase: 77800002  ObjectTable: ffffb088f3ac8880  HandleCount:  33.\n    Image: WindowsInspector.Controller.exe\n    VadRoot ffff890629929300 Vads 22 Clone 0 Private 353. Modified 0. Locked 257.\n    DeviceMap ffffb088f43ed730\n    Token                             ffffb088f6f88060\n    ElapsedTime                       00:53:33.825\n    UserTime                          00:00:00.000\n    KernelTime                        00:00:00.000\n    QuotaPoolUsage[PagedPool]         24560\n    QuotaPoolUsage[NonPagedPool]      3256\n    Working Set Sizes (now,min,max)  (846, 50, 345) (3384KB, 200KB, 1380KB)\n    PeakWorkingSetSize                814\n    VirtualSize                       4143 Mb\n    PeakVirtualSize                   4143 Mb\n    PageFaultCount                    849\n    MemoryPriority                    BACKGROUND\n    BasePriority                      8\n    CommitCharge                      540\n\n        THREAD ffff890629432080  Cid 06f8.0c6c  Teb: 0000003877759000 Win32Thread: 0000000000000000 RUNNING on processor 0\n```\n\nThis is how to show a little bit information about the current process:\n\n```\nkd\u003e !process -1 0\nPROCESS ffff8e8aa3781080\n    SessionId: 1  Cid: 0a20    Peb: 62982f2000  ParentCid: 13ec\n    DirBase: 6b280002  ObjectTable: ffffc68158f6da00  HandleCount: 486.\n    Image: PROCEXP64.exe\n```\n\n### Searching for processes\n\n- Use the \"!process\" command with wildcards: \u003ccode\u003e!process \"Windows*\"\u003c/code\u003e\n\n### Moving to the context of a certain process\n\nMoving between process contexts allows placing breakpoints on the process (in user mode), seeing the state of the process, \nsearching symbols (because the symbols are loaded)\n  \n- Get the EPROCESS address : \u003ccode\u003e!process 0 0 myproc.exe\u003c/code\u003e\n- Use the address to switch context: \u003ccode\u003e.process /i \u003cEPROCESS address\u003e\u003c/code\u003e\n- Continue until the scheduler switches to the desired process context: \u003ccode\u003eg\u003c/code\u003e\n\n```\nkd\u003e .process /i ffff998ba6f6e280\nYou need to continue execution (press 'g' \u003center\u003e) for the context\nto be switched. When the debugger breaks in again, you will be in\nthe new process context.\nkd\u003e g\nInvalid parameter passed to C runtime function.\nBreak instruction exception - code 80000003 (first chance)\nrax=0000000000000000 rbx=00000000000000bd rcx=0000000000000007\nrdx=0000000000000000 rsi=0000000000000000 rdi=ffff998ba6f6e280\nrip=fffff8041be59240 rsp=ffff840136f67a58 rbp=ffff998ba6f6e280\n r8=ffff998ba557b0e8  r9=7ffff8041c60c600 r10=ffff840136f67a90\nr11=0000000000000000 r12=0000000000000700 r13=0000000000000000\nr14=0000000000000000 r15=fffff8041c1fb200\niopl=0         nv up ei ng nz na pe nc\ncs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282\nnt!DbgBreakPointWithStatus:\nfffff804`1be59240 cc              int     3\nkd\u003e !process\nPROCESS ffff998ba6f6e280\n    SessionId: 0  Cid: 08e4    Peb: 00684000  ParentCid: 032c\n    DirBase: 5e3d0002  ObjectTable: ffffbf8f1ddf8740  HandleCount: 397.\n    Image: vmtoolsd.exe\n    VadRoot ffff998ba57e97a0 Vads 176 Clone 0 Private 1675. Modified 7635. Locked 0.\n    DeviceMap ffffbf8f19413600\n    Token                             ffffbf8f1d65c060\n    ElapsedTime                       02:23:51.459\n    UserTime                          00:00:00.015\n    KernelTime                        00:00:00.031\n    QuotaPoolUsage[PagedPool]         205840\n    QuotaPoolUsage[NonPagedPool]      24888\n    Working Set Sizes (now,min,max)  (1560, 50, 345) (6240KB, 200KB, 1380KB)\n    PeakWorkingSetSize                5419\n    VirtualSize                       4236 Mb\n    PeakVirtualSize                   4245 Mb\n    PageFaultCount                    22400\n    MemoryPriority                    BACKGROUND\n    BasePriority                      13\n    CommitCharge                      2308\n```\n\nThat allows us to put breakpoints in the context of this process.\n\n### Debugging User Mode Code From a Kernel Debugging Session\n\nNote that the Timestamp and Checksum of the image must be valid. If the image doesn't have a valid checksum/timestamp, windbg will not\nbe able to load the symbols. Compiling the executable with vs2019 results in an invalid checksum by default (on debug builds) because\nof a feature called \"incremental build\". It's best to debug the process with release builds or disable incremental builds.\n\nAdd the .pdb path of your user mode application into the source file path. Without doing so, WinDbg might get stuck if you use reload /f\nwhile trying to get the symbols (https://stackoverflow.com/questions/38062216/windbg-cant-find-microsoft-symbols).\nAfter that, perform \u003ccode\u003e.reload\u003c/code\u003e to reload symbols (in the context of this process). Then, \"lm\" should show the user mode\nimage that you are debugging.\n\nThat will allow to put breakpoints by using symbols from this image. :)\n\n## Debugging RPC \n\n- Set a breakpoint on RPC method invocation: ```bp RPCRT4!Invoke```\n\nTo get the THREAD id, use the following structures:\n\n```C\n\nPTHREAD ThreadPtr = Teb-\u003eReservedForNtRpc ^ 0x0ABABABABDEDEDEDE;\n\nclass THREAD { \n\tULONGLONG ThreadId; // 0x10\n\tRpcCallState* RpcMessage; // 0x20\n}\n\n\nclass RpcCallState { \n\tRpcConnectionInformation* RpcConnectionInfo; // 0x130\n\tPPORT_MESSAGE PortMessage; // 0x1b8\n}\n\nclass RpcConnectionInformation { \n\tAlpcConnectionInformation* AlpcConnectionInformation; // 0x38\n}\n\nclass AlpcConnectionInformation { \n\tHANDLE PortHandle; // 0xd0\n}\n```\n\n\n## Threads\n\n```!thread```\n\n\n## Pool Allocation Breakpoint\n\nThis trick is very useful - it can be used to break when a certain tag is used in an allocation.\n\n```dd nt!PoolHitTag L1``` - read the current pool tag hit\n```ed nt!PoolHitTag 'eliF'``` - set the current pool tag hit to 'File'. Each time a file will be allocated, we'll break\n\n\n## Debugger Expressions\n\nthe ```dx``` command is one of the most useful commands of windbg. It can be used to evaluate a C++ like expressions in the debugger.\nThe reason it's so powerfull is that it let's you access symbol information and javascript windbg scripts.\n\nSome simple examples (More examples later)\n\n\n## Windbg Scripting\n..\n..\n..\n\n## Dotnet Debugging\n\n- .NET Internals: https://docs.microsoft.com/en-us/archive/msdn-magazine/2005/may/net-framework-internals-how-the-clr-creates-runtime-objects\n\n\nThe SOS (Son Of Strike) Windbg extension can be used to debug .NET processes.\n\n### Origin of the name\n\n*The original name of the CLR team (chosen by team founder and former Microsoft Distinguished Engineer Mike Toutonghi) was \"Lighting\". Larry Sullivan's dev team created an ntsd extension dll to help facilitate the bootstrapping of v1.0. We called it strike.dll (get it? \"Lightning Strike\"? yeah, I know, ba'dump bum). PSS really needed this in order to give us information back to the team when it was time to debug nasty stress failures, which are almost always done with the Windows debugger stack. But we didn't want to hand out our full strike.dll, because it contained some \"dangerous\" commands that if you really didn't have our source code could cause you confusion and pain (even to other Microsoft teams). So I pushed the team to create \"Son of Strike\" (Simon from our dev takes credit/blame for this), and we shipped it with the product starting with Everett (aka V1.1).*\n\n\n\n### Loading the SOS plugin\n\nThe SOS windbg extension is loaded from the .NET runtime DLL. First we have to make sure mscorlib is loaded into the process. if not (or, it's a dump) We first put a breakpoint on the MSCORLIB DLL (A .NET DLL that provides the .NET standard libraries)\n\n```\n\u003e sxe ld:mscorlib\n\u003e g\n```\n\nFor example:\n\n```\nntdll!RtlUserThreadStart:\n00007ffb`0290ce30 4883ec78        sub     rsp,78h\n0:007\u003e sxe ld:mscorlib\n0:007\u003e g\n...\n...\nModLoad: 00007ffa`d3500000 00007ffa`d43e4000   C:\\windows\\assembly\\NativeImages_v2.0.50727_64\\mscorlib\\712d042affe876859328e2d4029c7297\\mscorlib.ni.dll\nntdll!NtMapViewOfSection+0x14:\n00007ffb`0293c574 c3              ret\n```\nAfter that, we can run a command to load the SOS plugin from the runtime DLL. the name of the runtime DLL was changed in .NET 4, so we have to specify a different name. \nThis command means: Load the \"sos\" plugin from a loaded DLL.\n\nTo determine the version of .NET, you can run 'lm' and see which DLL is loaded:\n\n- mscorwks: .NET 2\n- clr: .NET 4\n\n##### .NET 2\n\n```\n.loadby sos mscorwks\n```\n\n##### .NET 4+\n\n```\n.loadby sos clr\n```\n\n#### Load SOS in a dump file\n\nIn dump files you get from other computers, you need to load dll using an absolute path. So first, you need to find the .net directory that matches the .NET version that you debug (2 vs 4) - then, you need to load sos.dll from this path. For example:\n\n```\n.load C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\sos.dll\n```\n\n### Loading into a Wow64 dump\n\nThere's a bug in sos.dll that it cannot load correctly into a wow64 dump because it \"thinks\" the target architecture is incorrect.\nTo solve this, you can use this Windbg plugin: https://github.com/poizan42/soswow64\n\n1. Load the dump into a Windbg x86 debugger. (It sometimes works with Windbgx64 debuggers too)\n2. load sos.dll\n3. load soswow64.dll\n4. switch to wow64 (wow64exts.sw)\n5. have fun!\n\nexample:\n\n```\n0:000\u003e .load C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\SOS.dll\n0:000\u003e .load C:\\Tools\\soswow64\\soswow64.dll\nSuccessfully hooked IDebugControl::GetExecutingProcessorType.\nSuccessfully patched DbgEng!X86MachineInfo::ConvertCanonContextToTarget.\n0:000\u003e !wow64exts.sw\nSwitched to Guest (WoW) mode\n0:000:x86\u003e !clrstack\nOS Thread Id: 0x1b20 (0)\nESP       EIP     \n0010fd70 0000002b [InlinedCallFrame: 0010fd70] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()\n0010fd6c 6e5a8e08 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)\n0010fe08 6e5a88f7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)\n0010fe5c 6e5a8741 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)\n0010fe8c 6eabe7f2 System.Windows.Forms.Application.Run()\n.......\n.......\n```\n\n### Finding information about a method/type\n\n- ```!dumpdomain``` - List all application domains.\n- ```!name2ee * \u003cfull method/type/assembly name\u003e``` can be used to find methods/types/assemblies\n  - Sometimes classes are missing when using !name2ee. Not sure why.\n- ```!dumpmt -md \u003cmethod_table_address\u003e``` - List all the methods in a method table. Each object has a method table\n- ```!DumpMD /d \u003cmethod_descriptor_address\u003e``` - Show information about a method descriptor.\n- ```!ip2md \u003caddress\u003e``` - get method descriptor by address. \n- ```!dumpil \u003cdescriptor\u003e``` - output IL disassembly of a method\n- ```!clrstack``` - show stack trace for CLR ONLY.\n- ```!dumpstack``` - show combined stack trace for CLR and native code.\n  - This command is not so reliable - it can sometimes show unrelated functions \n- ```!do \u003cobject_address\u003e``` - Dump a managed object\n- ```!dso``` - Dump the objects on the stack\n- ```!threads``` - list the managed threads and can be used to change context to a different thread\n- ```!dumpmodule -mt \u003cmodule\u003e``` - List method tables in a module\n\n### Managed breakpoints\n\nThere are 2 ways to put a breakpoint on a managed method:\n\n1. Find the address of jitted code using ```!dumpmd``` and use the regular ```bp``` command.\n2. If the method is not jitted yet, you can use the ```!bpmd``` command.\n\n\n## Minifilter Debugging\n\n....\n\n\n## TODO\n\n- dps\n- .reload /f\n- kdfiles: drvmap\n- kdinit\n- disassembly: u, uf, uf /c\n- !pte\n- .formats\n- dv\n- .f+ / .f- (Or Ctrl Up/Down)\n- !thread\n- !handle \u003chandle\u003e\n- error \u003cntstatus\u003e\n- !devobj\n- !drvobj\n- !object\n- !error \u003cwin32_error\u003e\n- !error \u003cntstatus\u003e nt\n- !devnode 0 1\n- lmu\n- ?? (_EPROCESS*)@@masm(nt!PsInitialSystemProcess)\n- .reload -user\t\n- dd, dq, dds, dqs dps\n.shell\n- .kdfiles -m file c:\\\\hostdir\\\\file.sys \u003c\u003c instead of creating a drv map file\n- dt poi(nt!PsLoadedModuleList) nt!_LDR_DATA_TABLE_ENTRY -l InLoadOrderLinks.Flink BaseDllName EntryPoint\n- dt \u003clist head address\u003e \u003cdata structure\u003e -l \u003cflink path\u003e \u003cvariables to print\u003e - if you are mistaken in the name of the flink member,\n\tit will show you only the first element in the list.\n- dt nt!_LDR_DATA_TABLE_ENTRY poi(nt!PsLoadedModuleList)\n- !poolfind\n- !kp, !kc\n- .frame \u003cid\u003e\n- !gflag +ksl, sxe ld dll_name\n- !ioctldecoder\n- %...%\\WindowsApps\\Microsoft.WinDbg_8wekyb3d8bbwe\\WinDbgX.exe -k com:pipe,resets=0,reconnect,port=$(pipename) -c \"$$\u003c c:\\tools\\virtualkd\\kdinit\"\n- CTRL-ALT-K - Enable boot breakpoint - remember to use \"Restart Guest\" and not simply a reset to keep the same windbg process\n- For vmware 15: https://github.com/4d61726b/VirtualKD-Redux\n- Use DbgKit for object exploration: http://www.andreybazhan.com/dbgkit.html\n- Use \"dx\" to explore processes, threads, ..\n- Use \"bp /w\" to set smart conditional breakpoints\n- Jump to address: r rip = fffff802`64c763f0 \n- dx -id 0, 0, \u003cprocess_object\u003e \u003cexpression\u003e\n- Change the value of register: r \u003creg_name\u003e = \u003creg_value\u003e\n- .pagein\n- !devnode + !devnode \u003caddress\u003e 1 - show device node tree\n- Breakpoint in process by name after DLLs are loaded: \n```\n\tbp /w \"@$curprocess.Name.ToLower() == \\\"apcinjector.exe\\\"\" nt!NtTestAlert \".reload;bp /t 1 apcinjector!main;g\"\n```\n- Wow64 Debugging: https://docs.microsoft.com/en-us/windows/win32/winprog64/debugging-wow64\n- .thread \u003caddress\u003e - set register context\n- Replace existing system drivers with kdfiles: https://kobyk.wordpress.com/2008/07/04/replacing-boot-load-drivers-with-the-windows-boot-debugger/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frepnz%2Fwindbg-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frepnz%2Fwindbg-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frepnz%2Fwindbg-cheat-sheet/lists"}