diff options
| author | Gabriel Schneider <[email protected]> | 2026-02-19 21:46:04 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-02-19 21:46:04 -0300 |
| commit | b17c9042060156c8b2bf6fe91ebcd6292c8419a6 (patch) | |
| tree | 5fd216621867fff6b544447dc8d91d09e548cebf | |
| parent | 632a8daeb6377bdfde47cf83dcffd116d88e999a (diff) | |
| download | codenomicon-b17c9042060156c8b2bf6fe91ebcd6292c8419a6.tar.gz codenomicon-b17c9042060156c8b2bf6fe91ebcd6292c8419a6.zip | |
added simple frida-gum build
| -rw-r--r-- | build.zig | 294 | ||||
| m--------- | deps/capstone | 0 | ||||
| -rw-r--r-- | src/elfo-pretty.zig | 103 |
3 files changed, 303 insertions, 94 deletions
@@ -11,11 +11,235 @@ pub fn build(b: *std.Build) !void { .link_libc = true, }); + const elfo = b.addExecutable(.{ + .name = "elfo-pretty", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/elfo-pretty.zig"), + .target = target, + .optimize = optimize, + }), + }); + + const capstone_lib = capstone(b, .{ + .optimize = optimize, + .target = target, + }); + + const frida_lib = gum_stalker(b, .{ + .optimize = optimize, + .target = target, + }); + + frida_lib.step.dependOn(&capstone_lib.step); + frida_lib.root_module.linkLibrary(capstone_lib); + + b.installArtifact(capstone_lib); + b.installArtifact(frida_lib); + + elfo.root_module.linkLibrary(capstone_lib); + elfo.root_module.addImport("capstone", capstone_lib.root_module); + + const gloves = b.addExecutable(.{ + .name = "gloves", + .root_module = gloves_module, + }); + + b.installArtifact(elfo); + b.installArtifact(gloves); + + const run_elfo_cmd = b.addRunArtifact(elfo); + const run_elfo_step = b.step("elfo", "See the pretty elfo!"); + run_elfo_step.dependOn(&run_elfo_cmd.step); + + const run_gloves_cmd = b.addRunArtifact(gloves); + const run_gloves_step = b.step("gloves", "See the pretty gloves!"); + run_gloves_step.dependOn(&run_gloves_cmd.step); + + // TODO: add flag to run on gdb +} + +fn gum_stalker(b: *std.Build, opts: struct { + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +}) *std.Build.Step.Compile { + const dep = b.dependency("frida-gum", .{}); + const capstone_dep = b.dependency("capstone", .{}); + + // stub gumenumtypes.h — normally generated by gnome.mkenums + const wf = b.addWriteFiles(); + _ = wf.add("gum/gumenumtypes.h", + \\#ifndef __GUM_ENUM_TYPES_H__ + \\#define __GUM_ENUM_TYPES_H__ + \\#include <glib-object.h> + \\G_BEGIN_DECLS + \\GType gum_elf_type_get_type (void) G_GNUC_CONST; + \\#define GUM_TYPE_ELF_TYPE (gum_elf_type_get_type ()) + \\GType gum_elf_osabi_get_type (void) G_GNUC_CONST; + \\#define GUM_TYPE_ELF_OSABI (gum_elf_osabi_get_type ()) + \\GType gum_elf_machine_get_type (void) G_GNUC_CONST; + \\#define GUM_TYPE_ELF_MACHINE (gum_elf_machine_get_type ()) + \\GType gum_elf_source_mode_get_type (void) G_GNUC_CONST; + \\#define GUM_TYPE_ELF_SOURCE_MODE (gum_elf_source_mode_get_type ()) + \\G_END_DECLS + \\#endif + ); + + // C-only module (translate-c can't handle GLib's _Pragma macros) + const c_mod = b.createModule(.{ + .target = opts.target, + .optimize = opts.optimize, + .link_libc = true, + }); + + // include paths for C source compilation + c_mod.addIncludePath(dep.path("")); + c_mod.addIncludePath(dep.path("gum")); + c_mod.addIncludePath(dep.path("gum/arch-x86")); + c_mod.addIncludePath(dep.path("gum/arch-arm")); + c_mod.addIncludePath(dep.path("gum/arch-arm64")); + c_mod.addIncludePath(dep.path("gum/arch-mips")); + c_mod.addIncludePath(dep.path("gum/backend-linux/include")); + c_mod.addIncludePath(dep.path("gum/backend-elf")); + c_mod.addIncludePath(dep.path("gum/backend-posix")); + c_mod.addIncludePath(dep.path("libs")); + c_mod.addIncludePath(dep.path("libs/gum/heap")); + c_mod.addIncludePath(dep.path("libs/gum/prof")); + c_mod.addIncludePath(capstone_dep.path("include/capstone")); + c_mod.addIncludePath(capstone_dep.path("include")); + c_mod.addIncludePath(wf.getDirectory()); + + // system libraries + c_mod.linkSystemLibrary("glib-2.0", .{}); + c_mod.linkSystemLibrary("gobject-2.0", .{}); + + // config defines — replaces meson's config.h + add_project_arguments + // platform / arch + c_mod.addCMacro("HAVE_LINUX", "1"); + c_mod.addCMacro("HAVE_I386", "1"); + c_mod.addCMacro("HAVE_ELF", "1"); + c_mod.addCMacro("HAVE_GLIBC", "1"); + // frida-gum options + c_mod.addCMacro("GUM_STATIC", "1"); + c_mod.addCMacro("GUM_USE_SYSTEM_ALLOC", "1"); + c_mod.addCMacro("FRIDA_VERSION", "\"16.x\""); + // compiler feature detection + c_mod.addCMacro("HAVE_SYNC_LOCK", "1"); + c_mod.addCMacro("HAVE_CLEAR_CACHE", "1"); + c_mod.addCMacro("HAVE_CLTZ", "1"); + c_mod.addCMacro("HAVE_POPCOUNT", "1"); + c_mod.addCMacro("HAVE_PACK_PRAGMA", "1"); + // system headers + c_mod.addCMacro("HAVE_ELF_H", "1"); + c_mod.addCMacro("HAVE_LINK_H", "1"); + c_mod.addCMacro("HAVE_STDINT_H", "1"); + c_mod.addCMacro("HAVE_SYS_AUXV_H", "1"); + c_mod.addCMacro("HAVE_ASM_PRCTL_H", "1"); + c_mod.addCMacro("HAVE_SYS_USER_H", "1"); + // system functions / types + c_mod.addCMacro("HAVE_MADVISE", "1"); + c_mod.addCMacro("HAVE_LONG_DOUBLE", "1"); + c_mod.addCMacro("HAVE_LONG_LONG_INT", "1"); + c_mod.addCMacro("HAVE_UNSIGNED_LONG_LONG_INT", "1"); + c_mod.addCMacro("HAVE_PTHREAD_ATTR_GETSTACK", "1"); + c_mod.addCMacro("HAVE_PTHREAD_SETNAME_NP", "1"); + // NOTE: HAVE_FRIDA_GLIB omitted — system GLib lacks frida's patches + // capstone compat (frida-gum uses capstone 5 type names) + c_mod.addCMacro("CAPSTONE_ARM_COMPAT_HEADER", "1"); + c_mod.addCMacro("CAPSTONE_AARCH64_COMPAT_HEADER", "1"); + c_mod.addCMacro("CAPSTONE_SYSTEMZ_COMPAT_HEADER", "1"); + // GLib / compiler flags + c_mod.addCMacro("_GNU_SOURCE", "1"); + c_mod.addCMacro("G_LOG_DOMAIN", "\"Frida\""); + c_mod.addCMacro("GLIB_VERSION_MIN_REQUIRED", "GLIB_VERSION_2_56"); + c_mod.addCMacro("G_DISABLE_DEPRECATED", ""); + + // core + arch writers (unconditional in upstream meson) + c_mod.addCSourceFiles(.{ + .root = dep.path("gum"), + .files = &.{ + "gum.c", + "gumapiresolver.c", + "gumbacktracer.c", + "gumcloak.c", + "gumcodeallocator.c", + "gumcodesegment.c", + // gumdarwingrafter.c and gumdarwinmodule.c omitted (darwin only) + "gumelfmodule.c", + "gumeventsink.c", + "gumexceptor.c", + "gumheapapi.c", + "guminterceptor.c", + "guminvocationcontext.c", + "guminvocationlistener.c", + "gumkernel.c", + "gumleb.c", + "gumlibc.c", + "gummemory.c", + "gummemorymap.c", + "gummetalarray.c", + "gummetalhash.c", + "gummoduleapiresolver.c", + "gummodulemap.c", + "gumprintf.c", + "gumprocess.c", + "gumthreadregistry.c", + "gummodule.c", + "gummodulefacade.c", + "gummoduleregistry.c", + "gumreturnaddress.c", + "gumspinlock.c", + "gumstalker.c", + "gumswiftapiresolver.c", + // arch writers (x86 only — arm/arm64/mips need frida's capstone fork) + "arch-x86/gumx86writer.c", + "arch-x86/gumx86relocator.c", + "arch-x86/gumx86reader.c", + // x86 backend + "arch-x86/gumx86backtracer.c", + "backend-x86/gumcpucontext-x86.c", + "backend-x86/gumprocess-x86.c", + "backend-x86/guminterceptor-x86.c", + "backend-x86/gumstalker-x86.c", + // linux + posix backend + "backend-linux/gummemory-linux.c", + "backend-posix/gummemory-posix.c", + "backend-linux/gumprocess-linux.c", + "backend-linux/gumthreadregistry-linux.c", + "backend-linux/gummoduleregistry-linux.c", + "backend-linux/gummodule-linux.c", + "backend-posix/gumtls-posix.c", + "backend-posix/gumexceptor-posix.c", + "backend-posix/gummemoryaccessmonitor-posix.c", + // elf backend + "backend-elf/gummodule-elf.c", + "backend-elf/gummoduleregistry-elf.c", + }, + }); + + // x86 assembly glue + c_mod.addAssemblyFile(dep.path("gum/backend-x86/gumstalker-x86-glue.S")); + + const stalker_lib = b.addLibrary(.{ + .name = "gumstalker", + .linkage = .static, + .root_module = c_mod, + }); + + stalker_lib.installHeadersDirectory(capstone_dep.path("include/capstone"), "capstone", .{}); + stalker_lib.installHeader(capstone_dep.path("include/platform.h"), "capstone/platform.h"); + + return stalker_lib; +} + +fn capstone(b: *std.Build, opts: struct { + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +}) *std.Build.Step.Compile { const capstone_dep = b.dependency("capstone", .{}); const translate_c = b.addTranslateC(.{ .root_source_file = capstone_dep.path("include/capstone/capstone.h"), - .target = target, - .optimize = optimize, + .target = opts.target, + .optimize = opts.optimize, .link_libc = true, }); @@ -32,27 +256,33 @@ pub fn build(b: *std.Build) !void { capstone_lib.root_module.addIncludePath(capstone_dep.path("include")); capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone")); capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone/X86")); + capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone/ARM")); capstone_lib.installHeadersDirectory(capstone_dep.path("include/capstone"), "capstone", .{}); capstone_lib.installHeader(capstone_dep.path("include/platform.h"), "capstone/platform.h"); - if (optimize == .Debug) capstone_lib.root_module.addCMacro("CAPSTONE_DEBUG", ""); + if (opts.optimize == .Debug) capstone_lib.root_module.addCMacro("CAPSTONE_DEBUG", ""); capstone_lib.root_module.addCMacro("CAPSTONE_HAS_X86", ""); + capstone_lib.root_module.addCMacro("CAPSTONE_HAS_ARM", ""); + capstone_lib.root_module.addCMacro("CAPSTONE_HAS_AArch64", ""); capstone_lib.root_module.addCMacro("CAPSTONE_BUILD_CSTOOL", "OFF"); - capstone_lib.root_module.addCMacro("CAPSTONE_USE_SYS_DYN_MEM", "OFF"); + capstone_lib.root_module.addCMacro("CAPSTONE_USE_SYS_DYN_MEM", "1"); + capstone_lib.root_module.addCMacro("CAPSTONE_BUILD_DIET", "1"); + capstone_lib.root_module.addCMacro("CAPSTONE_X86_REDUCE", "1"); capstone_lib.root_module.addCSourceFiles(.{ .root = capstone_dep.path(""), .files = common_sources }); - // capstone_lib.root_module.addCSourceFiles(.{ - // .root = capstone_dep.path("arch/AArch64"), - // .files = &.{ - // "AArch64BaseInfo.c", - // "AArch64Disassembler.c", - // "AArch64DisassemblerExtension.c", - // "AArch64InstPrinter.c", - // "AArch64Mapping.c", - // "AArch64Module.c", - // }, - // }); + + capstone_lib.root_module.addCSourceFiles(.{ + .root = capstone_dep.path("arch/ARM"), + .files = &.{ + "ARMBaseInfo.c", + "ARMDisassembler.c", + "ARMDisassemblerExtension.c", + "ARMInstPrinter.c", + "ARMMapping.c", + "ARMModule.c", + }, + }); capstone_lib.root_module.addCSourceFiles(.{ .root = capstone_dep.path("arch/X86"), .files = &.{ @@ -66,40 +296,8 @@ pub fn build(b: *std.Build) !void { }, }); - b.installArtifact(capstone_lib); - - const elfo = b.addExecutable(.{ - .name = "elfo-pretty", - .root_module = b.createModule(.{ - .root_source_file = b.path("src/elfo-pretty.zig"), - .target = target, - .optimize = optimize, - }), - }); - - elfo.root_module.linkLibrary(capstone_lib); - elfo.root_module.addImport("capstone", capstone_lib.root_module); - - const gloves = b.addExecutable(.{ - .name = "gloves", - .root_module = gloves_module, - }); - - // elfo.linkLibrary(cs.artifact); - b.installArtifact(elfo); - b.installArtifact(gloves); - - const run_elfo_cmd = b.addRunArtifact(elfo); - const run_elfo_step = b.step("elfo", "See the pretty elfo!"); - run_elfo_step.dependOn(&run_elfo_cmd.step); - - const run_gloves_cmd = b.addRunArtifact(gloves); - const run_gloves_step = b.step("gloves", "See the pretty gloves!"); - run_gloves_step.dependOn(&run_gloves_cmd.step); - - // TODO: add flag to run on gdb + return capstone_lib; } - const common_sources: []const []const u8 = &.{ "cs.c", "Mapping.c", diff --git a/deps/capstone b/deps/capstone deleted file mode 160000 -Subproject 90c3e2512286b077631da5361708562e333ae85 diff --git a/src/elfo-pretty.zig b/src/elfo-pretty.zig index ea0b246..1482670 100644 --- a/src/elfo-pretty.zig +++ b/src/elfo-pretty.zig @@ -1,58 +1,29 @@ const std = @import("std"); const cs = @import("capstone"); -const SymbolRange = struct { - start: u64, - end: u64, - name: []u8, - kind: u8, -}; - -fn iterateSymbols( - h: std.elf.Header, - file_reader: *std.Io.File.Reader, - symtab: std.elf.Elf64_Shdr, -) SymbolIterator { - return .{ - .elf_header = h, - .file_reader = file_reader, - .symtab = symtab, - }; -} - -const SymbolIterator = struct { - elf_header: std.elf.Header, - file_reader: *std.Io.File.Reader, - symtab: std.elf.Elf64_Shdr, - index: usize = 0, - - pub fn next(it: *SymbolIterator) !?std.elf.Elf64_Sym { - defer it.index += 1; - - const size: u64 = if (it.elf_header.is_64) @sizeOf(std.elf.Elf64_Sym) else @sizeOf(std.elf.Elf64_Sym); - const offset = it.symtab.sh_offset + size * it.index; - - if (offset >= (it.symtab.sh_size + it.symtab.sh_offset)) - return null; - - try it.file_reader.seekTo(offset); - return try it.file_reader.interface.takeStruct(std.elf.Elf64_Sym, it.elf_header.endian); - } -}; - pub fn main(init: std.process.Init) !void { - // var args = init.environ_map.iterator(); - // _ = args.next(); // skip argv[0] + var args = try init.minimal.args.iterateAllocator(init.gpa); + defer args.deinit(); + _ = args.next(); // skip argv[0] var buffer: [64]u8 = undefined; const stderr = try init.io.lockStderr(&buffer, .escape_codes); + // TODO: finish passing custom alloc operations here + // const mem_config: cs.cs_opt_mem = undefined; + // std.debug.assert(cs.cs_option(0, cs.CS_OPT_MEM, @intFromPtr(&mem_config)) == cs.CS_ERR_OK); + + var handle: usize = undefined; + defer _ = cs.cs_close(@ptrCast(&handle)); + // TODO: read the arch from the elf so we open the equivalent capstone handle + std.debug.assert(cs.cs_open(cs.CS_ARCH_X86, cs.CS_MODE_64, @ptrCast(&handle)) == cs.CS_ERR_OK); + try printElf( init.gpa, init.io, - // args.next() orelse "./study-samples/split", - "./study-samples/split", + args.next() orelse "./study-samples/split", stderr.terminal(), + handle, .{ // .show_unaddressable_sections = true, // .skip_sections_content = true, @@ -65,6 +36,7 @@ pub fn printElf( io: std.Io, path: []const u8, term: std.Io.Terminal, + handle: usize, options: struct { show_unaddressable_sections: bool = false, skip_sections_content: bool = false, @@ -79,9 +51,6 @@ pub fn printElf( var reader = f.reader(io, buffer); const header = try std.elf.Header.read(&reader.interface); - var handle: usize = undefined; - std.debug.assert(cs.cs_open(cs.CS_ARCH_X86, cs.CS_MODE_64, @ptrCast(&handle)) == cs.CS_ERR_OK); - const shstrtab = blk: { var section_it = header.iterateSectionHeaders(&reader); var section_idx: u32 = 0; @@ -282,6 +251,9 @@ pub fn printElf( if (section.sh_type == std.elf.SHT_PROGBITS and (section.sh_flags & (std.elf.SHF_ALLOC | std.elf.SHF_EXECINSTR)) != 0) { const instrs: []cs.cs_insn = blk: { var insn: [*]cs.cs_insn = undefined; + // TODO: use iter API + // https://www.capstone-engine.org/iteration.html + // const count = cs.cs_disasm_iter(handle, section_slice.?.ptr, section_slice.?.len, section.sh_addr, @ptrCast(&insn)); const count = cs.cs_disasm(handle, section_slice.?.ptr, section_slice.?.len, section.sh_addr, 0, @ptrCast(&insn)); break :blk insn[0..count]; }; @@ -467,3 +439,42 @@ pub fn dumpHexFallible( try bw.writeByte('\n'); } } + +const SymbolRange = struct { + start: u64, + end: u64, + name: []u8, + kind: u8, +}; + +fn iterateSymbols( + h: std.elf.Header, + file_reader: *std.Io.File.Reader, + symtab: std.elf.Elf64_Shdr, +) SymbolIterator { + return .{ + .elf_header = h, + .file_reader = file_reader, + .symtab = symtab, + }; +} + +const SymbolIterator = struct { + elf_header: std.elf.Header, + file_reader: *std.Io.File.Reader, + symtab: std.elf.Elf64_Shdr, + index: usize = 0, + + pub fn next(it: *SymbolIterator) !?std.elf.Elf64_Sym { + defer it.index += 1; + + const size: u64 = if (it.elf_header.is_64) @sizeOf(std.elf.Elf64_Sym) else @sizeOf(std.elf.Elf64_Sym); + const offset = it.symtab.sh_offset + size * it.index; + + if (offset >= (it.symtab.sh_size + it.symtab.sh_offset)) + return null; + + try it.file_reader.seekTo(offset); + return try it.file_reader.interface.takeStruct(std.elf.Elf64_Sym, it.elf_header.endian); + } +}; |
