{"id":29285888,"url":"https://github.com/lordmilko/debugtools","last_synced_at":"2025-08-12T13:05:21.171Z","repository":{"id":75540830,"uuid":"603591458","full_name":"lordmilko/DebugTools","owner":"lordmilko","description":".NET Debugging/Reverse Engineering Toolkit","archived":false,"fork":false,"pushed_at":"2023-12-23T23:59:46.000Z","size":1041,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-05T23:13:20.800Z","etag":null,"topics":["debugging","net-framework","netcore","powershell","profiling","reverse-engineering"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lordmilko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-02-19T01:12:22.000Z","updated_at":"2025-01-12T01:44:24.000Z","dependencies_parsed_at":"2023-03-11T19:58:45.702Z","dependency_job_id":"af481cfd-57a3-47bd-9e65-d3daa5ce7481","html_url":"https://github.com/lordmilko/DebugTools","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/lordmilko/DebugTools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lordmilko%2FDebugTools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lordmilko%2FDebugTools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lordmilko%2FDebugTools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lordmilko%2FDebugTools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lordmilko","download_url":"https://codeload.github.com/lordmilko/DebugTools/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lordmilko%2FDebugTools/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270065426,"owners_count":24520946,"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","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["debugging","net-framework","netcore","powershell","profiling","reverse-engineering"],"created_at":"2025-07-05T23:12:40.494Z","updated_at":"2025-08-12T13:05:21.154Z","avatar_url":"https://github.com/lordmilko.png","language":"C#","readme":"# DebugTools\n\n[![Appveyor status](https://ci.appveyor.com/api/projects/status/oblsum6rqdg3wmw8?svg=true)](https://ci.appveyor.com/project/lordmilko/debugtools)\n\n*DebugTools* is a PowerShell based toolkit for debugging and reverse engineering .NET programs.\n\nThe following outlines some of the major capabilities of *DebugTools*\n\n## Profiler\n\nHave you ever looked at a .NET application and asked yourself\n\n* What does this button do?\n* Why isn't something appearing in my search results?\n* How does this work?\n* Which file is the code for this in?\n\nAnswering such questions can often turn into hours long ordeals, slowly stepping in and around the target application using a debugger such as dnSpy. You don't know *exactly* what you're looking for, but you'll know it when you see it. Wouldn't it be nice though if, instead of manually stepping through the program, you could just *record* every single thing the program did, and then poke at this recording to get the data that you need?\n\nThis is exactly what the DebugTools Profiler does. Except where otherwise stated, all cmdlets provided by *DebugTools* should work with both .NET Framework and .NET Core.\n\n### Example\n\nSuppose you want to understand what the `gci` command does in PowerShell.\n\nFirst, we'll launch a new instance of PowerShell, and specify that we want to perform detailed tracing of method parameters/return values\n\n```powershell\n# Original PowerShell Prompt\nC:\\\u003e Start-DbgProfiler powershell -Detailed\n```\nWe don't enable tracing method calls on the target process until it's fully initialized. This allows the target process to not only startup faster, but also reduces the amount of noise we'll need to cut through when we get to the analysis stage.\n\nOnce the target process has fully initialized, we begin tracing the target process\n\n```powershell\n# Original PowerShell Prompt\nC:\\\u003e Trace-DbgProfilerStack\n```\nIn the target process, execute the `gci` command\n\n```powershell\n# Target PowerShell Prompt\nC:\\\u003e gci\n```\nWhen the results of the `gci` command have finished outputting, switch back to the original PowerShell prompt and hit Ctrl+C to stop recording\n\n```powershell\n# Original PowerShell Prompt\nCtrl+C\n```\nThe root frames of all threads will be emitted to the pipeline. Each Profiler Session that you start automatically caches its last recorded trace. If a trace is not explicitly specified to an analysis cmdlet,\nthe last recorded trace will implicitly be used.\n\nWe can assume that the \"gci\" command we executed was passed as a string to a variety of methods in order to translate it into an actual command. We can immediately view the unique call stacks of all methods that the value `gci` was passed into by maximizing our original PowerShell window and then using the following command\n\n```powershell\n# Show the call stacks of any methods where the value \"gci\" was passed in (either as a raw string or\n# a sub-member). Only show the first invocation of each method, and exclude namespace gunk from the\n# resulting output (Tip: you can also specify parameter -Simple which implies -Unique -ExcludeNamespace)\nC:\\\u003e Show-DbgProfilerStackTrace -StringValue gci -Unique -ExcludeNamespace\n```\n\n![gci output](https://raw.githubusercontent.com/lordmilko/DebugTools/master/assets/gci.png)\n\nAmongst the returned output, we spot an interesting sequence of events: inside of `InvokePipeline`, `AddCommand` tries to discover what the command `gci` command is. As part of `TryNormalSearch` it considers the possibility that `gci` might be an alias. And then sure enough, it resolves the alias `gci` to `Get-ChildItem`.\n\nIt seems reasonable to assume that after the `AddCommand` method finished, the parent `InvokePipeline` method invoked some other sequence of methods,\nultimately leading to the `Get-ChildItem` being invoked. While we could dump all of the frames called from `InvokePipeline` and eyeball the output (which could be quite a bit) for methods that look relevant, given we know the command `Get-ChildItem` is being invoked, let's filter for any frames containing the wildcard expression `*childitem*`.\n\n![called from](https://raw.githubusercontent.com/lordmilko/DebugTools/master/assets/calledfrom.png)\n\nFrom this, we can clearly see that the implementation of `Get-ChildItem` is a class aptly named `GetChildItemCommand`. To find which module this type is defined in, we can use the `Get-DbgProfilerMethod` command.\n\n```powershell\nC:\\\u003e Get-DbgProfilerMethod -TypeName *GetChildItem*\n```\n\nThings you can do with the DebugTools Profiler\n\n* Record all frame transitions that occur during process startup, or within a given window after the process has fully initialized\n* Capture values passed to and from functions, including class/struct members a customizable number of levels deep\n* Output, in real time, frames that occur that match a complex set of search criteria\n* Enumerate all methods that were invoked in the last trace, or since process startup\n* Search for frames in the last trace session that match a variety of complex conditions\n* Visualize a stack trace as a tree, excluding duplicate frames and highlighting frames that match certain conditions\n* List exceptions that occurred in the process, including where they were both thrown and handled from\n* Blacklist or whitelist assemblies to reduce the amount of noise you have to dig through\n\nNote: DebugTools Profiler does *not* currently support multiple appdomains. To what extent the profiler can be used against an application utilizing multiple appdomains is untested and unknown.\n\nFor more information on using the DebugTools Profiler, please see the [wiki](https://github.com/lordmilko/DebugTools/wiki).\n\n## SOS\n\nTypically, in order to do low level analytics of .NET programs you need to attach to the target process using WinDbg, load SOS and then run a command to extract the data you need. DebugTools contains a collection of cmdlets that perform some of the same key queries, using the underlying `ISOSDacInterface` API against running processes.\n\nActions you can perform using DebugTools' SOS cmdlets include\n\n* Enumerate AppDomains, Assemblies, Modules, MethodTables, MethodDescs and FieldDescs\n* Show a live stack trace (will pause and then resume the target process)\n\nFor more information please see the [wiki](https://github.com/lordmilko/DebugTools/wiki).\n\n## COM\n\nWhen attempting to reverse engineer programs that make heavy use of COM (e.g. Visual Studio), you can easily find yourself trying to figure out the native type a given interface is implemented in so you can poke at it further using a program such as IDA Pro. This process can often be laborious and involve a large\namount of trial and error.\n\nSuppose you want to know the native type that implements the `IVsSolution` interface within Visual Studio.\n\nFirst, we a establish a connection to the target process\n\n```powershell\nC:\\\u003e Connect-SOSProcess 75042\n```\nAnd then enumerate all objects that implement an interface whose name contains \"solution\" in it\n\n```powershell\nC:\\\u003e Get-ComObject *solution*\n```\n\nNote: due to issues encountered using newer versions of ClrMD, this feature currently uses an older version of ClrMD, and as such may or may not support newer .NET Core runtime versions.\n\n## Other\n\nTrying to reverse something, and need to know what types/assemblies implement a specific interface? The `Get-ClrType` cmdlet can help you out!\n\n```powershell\n# Get all types that implement the IServiceProvider interface that contain \"Ole\" in their names\nGet-ClrType \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\" -Interface IServiceProvider -Name *Ole*\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flordmilko%2Fdebugtools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flordmilko%2Fdebugtools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flordmilko%2Fdebugtools/lists"}