mirror of
https://github.com/whokilleddb/stacktracer
synced 2026-06-06 17:00:04 +00:00
Update README
This commit is contained in:
@@ -1 +1,65 @@
|
||||
# StackTracer
|
||||
# StackTracer
|
||||
|
||||
[](https://www.buymeacoffee.com/whokilleddb)
|
||||
|
||||
The goal of this project is find valid stack frames which you can replicate in your payloads. In C2s like BRC4, you can specify a stack frame which looks legit - and this can help in increasing the evasiveness of your shellcode. Using this tool you can examine legit processes for their stack frames and copy them over.
|
||||
|
||||
## Building
|
||||
|
||||
Building this tool is as easy as rust makes it:
|
||||
|
||||
```
|
||||
$ cargo build --release
|
||||
```
|
||||
|
||||
Note that you might need to install the `x86_64-pc-windows-gnu` toolchain
|
||||
|
||||
## Usage:
|
||||
|
||||
To view a detailed usage guide, you can pass the `--help` flag:
|
||||
|
||||
```
|
||||
Z:\> stackfinder.exe --help
|
||||
_____ _ _ _______
|
||||
/ ____| | | |__ __|
|
||||
| (___ | |_ __ _ ___| | _| |_ __ __ _ ___ ___ _ __
|
||||
\___ \| __/ _` |/ __| |/ / | '__/ _` |/ __/ _ \ '__|
|
||||
____) | || (_| | (__| <| | | | (_| | (_| __/ |
|
||||
|_____/ \__\__,_|\___|_|\_\_|_| \__,_|\___\___|_|
|
||||
DB @whokilleddb
|
||||
|
||||
A rust program to print the stack trace of a given thread
|
||||
|
||||
Usage: stackfinder.exe [OPTIONS] --pid <pid>
|
||||
|
||||
Options:
|
||||
--pid <pid> Process ID
|
||||
--tid <tid> Thread ID (defaults to 0) [default: 0]
|
||||
--hide-banner Hide the banner
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
```
|
||||
|
||||
The only required option is the `--pid` flag. To enumerate a process without targetting a particular thread, you go like:
|
||||
|
||||
```
|
||||
Z:\> stackfinder.exe --pid 1234
|
||||
```
|
||||
|
||||
To enumerate a specific thread, you can specify the ThreadID using the `--tid` flag:
|
||||
|
||||
```
|
||||
Z:\>.\stackfinder.exe --pid 3688 --tid 7336
|
||||
_____ _ _ _______
|
||||
/ ____| | | |__ __|
|
||||
| (___ | |_ __ _ ___| | _| |_ __ __ _ ___ ___ _ __
|
||||
\___ \| __/ _` |/ __| |/ / | '__/ _` |/ __/ _ \ '__|
|
||||
____) | || (_| | (__| <| | | | (_| | (_| __/ |
|
||||
|_____/ \__\__,_|\___|_|\_\_|_| \__,_|\___\___|_|
|
||||
DB @whokilleddb
|
||||
|
||||
PID | TID | STACK FRAME
|
||||
3688 | 7336 | win32u.dll!NtUserWaitMessage+0x14,USER32.DLL!IsDialogMessageA+0x3ba,USER32.DLL!Ordinal2635+0x267,USER32.DLL!SoftModalMessageBox+0x5b6,USER32.DLL!MessageBoxIndirectA+0x562,USER32.DLL!MessageBoxTimeoutW+0x18f,USER32.DLL!MessageBoxTimeoutA+0x100,USER32.DLL!MessageBoxA+0x45,0x25c70680050,KERNEL32.DLL+0x0
|
||||
```
|
||||
|
||||
_Hope this helps!_
|
||||
|
||||
+8
-15
@@ -5,9 +5,8 @@ use std::path::Path;
|
||||
use winapi::shared::minwindef::{DWORD, FALSE};
|
||||
// use winapi::shared::ntdef::NULL;
|
||||
use winapi::um::dbghelp::{
|
||||
AddrModeFlat, IMAGEHLP_MODULEW64, STACKFRAME64, SYMBOL_INFOW, SYMOPT_DEFERRED_LOADS,
|
||||
SYMOPT_UNDNAME, StackWalk64, SymFromAddrW, SymFunctionTableAccess64, SymGetModuleBase64,
|
||||
SymGetModuleInfoW64,
|
||||
AddrModeFlat, IMAGEHLP_MODULEW64, STACKFRAME64, SYMBOL_INFOW, StackWalk64, SymFromAddrW,
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, SymGetModuleInfoW64,
|
||||
};
|
||||
use winapi::um::errhandlingapi::GetLastError;
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
@@ -18,9 +17,6 @@ use winapi::um::winnt::{
|
||||
};
|
||||
|
||||
const MAX_SYM_NAME_LEN: usize = 512;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Resolve a single PC address to "module.dll!Symbol+0xNN" / "module.dll+0xNN"
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn resolve_address(h_process: HANDLE, addr: u64) -> String {
|
||||
unsafe {
|
||||
@@ -41,9 +37,6 @@ fn resolve_address(h_process: HANDLE, addr: u64) -> String {
|
||||
String::new()
|
||||
};
|
||||
|
||||
// ── 2. Try to resolve to a symbol via SymFromAddrW ──
|
||||
// SYMBOL_INFOW has a trailing `Name[1]` flexible-array member;
|
||||
// we over-allocate to hold up to MAX_SYM_NAME_LEN wide characters.
|
||||
let buf_size = mem::size_of::<SYMBOL_INFOW>() + MAX_SYM_NAME_LEN * mem::size_of::<u16>();
|
||||
let mut buf = vec![0u8; buf_size];
|
||||
let sym = buf.as_mut_ptr() as *mut SYMBOL_INFOW;
|
||||
@@ -52,6 +45,7 @@ fn resolve_address(h_process: HANDLE, addr: u64) -> String {
|
||||
|
||||
let mut sym_displacement: u64 = 0;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
|
||||
if SymFromAddrW(h_process, addr, &mut sym_displacement, sym) != 0 {
|
||||
// We have a symbol name (wide)
|
||||
let name_slice =
|
||||
@@ -113,7 +107,7 @@ pub fn trace_thread_stack(pid: u32, h_process: HANDLE, tid: u32) {
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
|
||||
let mut entries: Vec<String> = Vec::new();
|
||||
// ── Walk the stack ──
|
||||
|
||||
loop {
|
||||
let ok = StackWalk64(
|
||||
IMAGE_FILE_MACHINE_AMD64 as DWORD,
|
||||
@@ -133,16 +127,15 @@ pub fn trace_thread_stack(pid: u32, h_process: HANDLE, tid: u32) {
|
||||
|
||||
entries.push(resolve_address(h_process, frame.AddrPC.Offset));
|
||||
}
|
||||
// ── Output ──
|
||||
|
||||
println!("PID\t| TID\t| STACK FRAME");
|
||||
if entries.is_empty() {
|
||||
println!("{} | {} | ", pid, tid);
|
||||
println!("{}\t| {}\t| ", pid, tid);
|
||||
} else {
|
||||
println!("{} | {} | {}", pid, tid, entries.join(","));
|
||||
println!("{}\t| {}\t| {}", pid, tid, entries.join(","));
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Initialize DbgHelp symbol handler
|
||||
// let opts = SymGetOptions();
|
||||
|
||||
if !h_thread.is_null() {
|
||||
CloseHandle(h_thread);
|
||||
|
||||
Reference in New Issue
Block a user