feat(profile): binana x64dbg-gen now generates a types file from C source headers

This commit is contained in:
phaneron 2024-07-17 01:37:26 -04:00
parent e3ec21ecec
commit 5d5630a6cb
19 changed files with 2961 additions and 354 deletions

View file

@ -1 +0,0 @@
CDataRecyler__Clear 0095CEC0 f end=0095CF39

View file

@ -0,0 +1 @@
CDataRecycler__Clear 0095CEC0 f end=0095CF39

2206
3.3.5a/x32dbg/types.json Normal file

File diff suppressed because it is too large Load diff

121
README.md
View file

@ -1,56 +1,65 @@
# binana
This repository hosts some work related to studying the original game binaries.
You can use the information here to get a headstart when working on the [Whoa project](https://github.com/whoahq/whoa).
# Header files
To make reverse engineering easier, C header files matching the original memory layout are provided.
## Importing headers
To use these headers in Ghidra,
1. go to `File` > `Parse C Source...`.
2. Select `clib.prf` as your parse configuration, and clear all source files and input paths.
3. Add the header `<game version>/include/main.h` to the `Source files to parse` combo box.
4. Add the path to `<game version>/include` to the `Include paths` combo box.
5. press `Parse to Program`.
TODO: equivalent guide for IDA Pro.
## Maintaining headers
Headers should be restricted at all times to the C programming language only. C++ syntax will break type analysis.
To convert C++ namespaces, use double-underscores. For instance:
```cpp
void Name::Space::Thing();
```
should become:
```c
void Name__Space__Thing();
```
# Symbol files
Symbol files are text files that map function names and data labels to addresses.
In this repo, `script/compile-symbols` is used to concatenate our organized symbol files into one big file (`<game version>/symbol/main.sym`).
To import this file to your Ghidra project,
1. go to `Window` > `Script Manager`
2. In the table view, lookup `ImportSymbolsScript.py`
3. Run the script
4. Enter the path to `<game version>/symbol/main.sym`
To refresh the `main.sym` file after changing one of the constituent symbol files:
```bash
script/compile-symbols <game version>
```
# binana
This repository hosts some work related to studying the original game binaries.
You can use the information here to get a headstart when working on the [Whoa project](https://github.com/whoahq/whoa).
# Header files
To make reverse engineering easier, C header files to match the original executable's memory layout are provided.
# Symbol files
Symbol files are text files that map addresses to functions and variables/data labels.
In this repo, `script/compile-symbols` is used to concatenate our organized symbol files into one big file (`<game version>/symbol/main.sym`).
To refresh the gigantic `main.sym` file after changing one of the source symbol files:
```bash
script/compile-symbols <game version>
```
# Loading information into Ghidra
## Importing headers
To import the main header file into your Ghidra project,
1. go to `File` > `Parse C Source...`.
2. Select `clib.prf` as your parse configuration, and clear all source files and input paths.
3. Add the header `<game version>/include/main.h` to the `Source files to parse` combo box.
4. Add the path to `<game version>/include` to the `Include paths` combo box.
5. press `Parse to Program`.
If all goes well, Data Type Manager will now contain the data structures from the headers.
## Importing symbols
To import the symbol file into your Ghidra project,
1. go to `Window` > `Script Manager`
2. In the table view, lookup `ImportSymbolsScript.py`
3. Run the script
4. Enter the path to `<game version>/symbol/main.sym`
# Loading information into x64dbg (x32dbg)
For ease of debugging, we provide x64dbg databases (generated by the Go tool from symbol maps), as well as x64dbg type information (generated by the same Go tool from the C headers).
## Importing database
To load the database information into x64dbg:
1. Open x96dbg.exe or x32dbg.exe directly
2. Load your game binary
3. Go to `File` > `Database` > `Import database`
4. Navigate to <game version>/x32dbg/game.dd32`.
## Importing types
To load the type information JSON file:
1. Open the binary in x32dbg.exe
2. in the console, type: `LoadTypes <full path to local binana repository>\x32dbg\types.json`

11
go.mod
View file

@ -2,10 +2,17 @@ module github.com/thunderbrewhq/binana
go 1.22.0
require github.com/spf13/cobra v1.8.1
require (
github.com/spf13/cobra v1.8.1
modernc.org/cc/v3 v3.41.0
)
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/pflag v1.0.5 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

18
go.sum
View file

@ -1,8 +1,12 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
@ -10,3 +14,13 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View file

@ -38,7 +38,6 @@ func init() {
x64dbg_gen.Flags().StringP("game", "g", "3.3.5a", "the game profile")
x64dbg_gen.Flags().StringP("module-name", "m", "wow.exe", "the name of the module")
x64dbg_gen.Flags().StringP("base-address", "b", "00400000", "the base address of the module")
x64dbg_gen.Flags().BoolP("compress", "c", false, "enable/disable lz4 compression of the x64dbg database")
rootCmd.AddCommand(x64dbg_gen)
}

View file

@ -1,117 +1,50 @@
package cmd
import (
"fmt"
"os"
"path/filepath"
"strconv"
"github.com/spf13/cobra"
"github.com/thunderbrewhq/binana/go/symfile"
"github.com/thunderbrewhq/binana/go/x64dbg"
)
func hex_address(u uint64) string {
return fmt.Sprintf("0x%x", u)
}
// rootCmd represents the base command when called without any subcommands
var x64dbg_gen = &cobra.Command{
Use: "x64dbg-gen",
Short: "Generate x64dbg database using a symfile",
Run: x64dbg_gen_func,
}
func x64dbg_gen_func(cmd *cobra.Command, args []string) {
compress, err := cmd.Flags().GetBool("compress")
if err != nil {
panic(err)
}
module_name, err := cmd.Flags().GetString("module-name")
if err != nil {
panic(err)
}
base_address_s, err := cmd.Flags().GetString("base-address")
if err != nil {
panic(err)
}
base_address, err := strconv.ParseUint(base_address_s, 16, 64)
if err != nil {
panic(err)
}
game_profile, err := cmd.Flags().GetString("game")
if err != nil {
panic(err)
}
symfile_path := filepath.Join(game_profile, "symbol", "main.sym")
file, err := os.Open(symfile_path)
if err != nil {
fmt.Println(err)
os.Exit(1)
return
}
table := new(symfile.InMemoryTable)
if err := symfile.Load(table, file); err != nil {
fmt.Println(err)
os.Exit(1)
return
}
file.Close()
fmt.Printf("loaded %d symbols\n", table.Len())
var dd x64dbg.Database
for _, entry := range table.Entries {
relative_start_address := entry.StartAddress - base_address
relative_end_address := relative_start_address
if entry.EndAddress != 0 {
relative_end_address = entry.EndAddress - base_address
// for x64dbg, the end address is the last instruction.
// for us, the end address is the address immediately after the last instruction.
relative_end_address -= 1
}
if relative_end_address < relative_start_address || relative_end_address-relative_start_address >= 10000 {
fmt.Printf("Wtf symbol %s %08x %08x (offset %d)\n", entry.Name, relative_start_address, relative_end_address, relative_end_address-relative_start_address)
}
// create label
var label x64dbg.Label
label.Manual = true
label.Address = hex_address(relative_start_address)
label.Text = entry.Name
label.Module = module_name
dd.Labels = append(dd.Labels, label)
if entry.Kind == symfile.Function {
var fn x64dbg.Function
fn.Manual = true
fn.Start = hex_address(relative_start_address)
fn.End = hex_address(relative_end_address)
fn.Module = module_name
fn.InstructionCount = hex_address(0)
fn.Parent = hex_address(relative_start_address)
dd.Functions = append(dd.Functions, fn)
}
}
dd_path := filepath.Join(game_profile, "x32dbg", "game.dd32")
if err = x64dbg.SaveDatabase(dd_path, &dd, compress); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
package cmd
import (
"fmt"
"os"
"strconv"
"github.com/spf13/cobra"
"github.com/thunderbrewhq/binana/go/profile"
)
var x64dbg_gen = &cobra.Command{
Use: "x64dbg-gen",
Short: "Generate x64dbg database using a symfile",
Run: x64dbg_gen_func,
}
func x64dbg_gen_func(cmd *cobra.Command, args []string) {
// get command line arguments
module_name, err := cmd.Flags().GetString("module-name")
if err != nil {
panic(err)
}
base_address_s, err := cmd.Flags().GetString("base-address")
if err != nil {
panic(err)
}
// parse the base address of game EXE
base_address, err := strconv.ParseUint(base_address_s, 16, 64)
if err != nil {
panic(err)
}
game_profile_directory, err := cmd.Flags().GetString("game")
if err != nil {
panic(err)
}
game_profile, err := profile.Open(game_profile_directory)
if err != nil {
panic(err)
}
if err = game_profile.CreateX64dbgFiles(module_name, base_address); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

View file

@ -0,0 +1,6 @@
#ifndef SYSTEM_STD_BOOL_H
#define SYSTEM_STD_BOOL_H
typedef char bool;
#endif

View file

@ -0,0 +1,17 @@
#ifndef SYSTEM_STD_INT_H
#define SYSTEM_STD_INT_H
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef int32_t ptrdiff_t;
typedef uint32_t uintptr_t;
typedef int32_t intptr_t;
#endif

51
go/profile/open.go Normal file
View file

@ -0,0 +1,51 @@
package profile
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"github.com/thunderbrewhq/binana/go/symfile"
)
type Profile struct {
Directory string
SymbolTable *symfile.InMemoryTable
}
func Open(profile_directory string) (profile *Profile, err error) {
var dir fs.FileInfo
dir, err = os.Stat(profile_directory)
if err != nil {
return
}
if !dir.IsDir() {
err = fmt.Errorf("profile: game profile is not a directory")
return
}
fmt.Println("Opening profile", profile_directory)
profile = new(Profile)
profile.Directory = profile_directory
path_to_symbols_file := filepath.Join(profile_directory, "symbol", "main.sym")
var symbols_file *os.File
symbols_file, err = os.Open(path_to_symbols_file)
if err != nil {
return
}
profile.SymbolTable = new(symfile.InMemoryTable)
if err = symfile.Load(profile.SymbolTable, symbols_file); err != nil {
return
}
symbols_file.Close()
//
return
}

13
go/profile/x64dbg.go Normal file
View file

@ -0,0 +1,13 @@
package profile
func (profile *Profile) CreateX64dbgFiles(module_name string, base_address uint64) (err error) {
if err = profile.generate_x64dbg_database(module_name, base_address); err != nil {
return
}
if err = profile.generate_x64dbg_types(); err != nil {
return
}
return
}

View file

@ -0,0 +1,66 @@
package profile
import (
"fmt"
"path/filepath"
"github.com/thunderbrewhq/binana/go/symfile"
"github.com/thunderbrewhq/binana/go/x64dbg"
)
func hex_address(u uint64) string {
return fmt.Sprintf("0x%x", u)
}
func (profile *Profile) generate_x64dbg_database(module_name string, base_address uint64) (err error) {
// Convert symbol table into x64dbg database
var dd x64dbg.Database
for _, entry := range profile.SymbolTable.Entries {
relative_start_address := entry.StartAddress - base_address
relative_end_address := relative_start_address
if entry.EndAddress != 0 {
relative_end_address = entry.EndAddress - base_address
// for x64dbg, the end address is the last instruction.
// for us, the end address is the address immediately after the last instruction.
relative_end_address -= 1
}
if relative_end_address < relative_start_address || relative_end_address-relative_start_address >= 10000 {
fmt.Printf("Strange symbol %s %08x %08x (offset %d)\n", entry.Name, relative_start_address, relative_end_address, relative_end_address-relative_start_address)
}
// create label
var label x64dbg.Label
label.Manual = true
label.Address = hex_address(relative_start_address)
label.Text = entry.Name
label.Module = module_name
dd.Labels = append(dd.Labels, label)
if entry.Kind == symfile.Function {
var fn x64dbg.Function
fn.Manual = true
fn.Start = hex_address(relative_start_address)
fn.End = hex_address(relative_end_address)
fn.Module = module_name
fn.InstructionCount = hex_address(0)
fn.Parent = hex_address(relative_start_address)
dd.Functions = append(dd.Functions, fn)
}
}
// save database
dd_path := filepath.Join(profile.Directory, "x32dbg", "game.dd32")
if err = x64dbg.SaveDatabase(dd_path, &dd); err != nil {
return
}
fmt.Println("database generated!", dd_path)
return
}

View file

@ -0,0 +1,236 @@
package profile
import (
"fmt"
"path/filepath"
"slices"
"sort"
"github.com/thunderbrewhq/binana/go/x64dbg"
"modernc.org/cc/v3"
)
func sort_string_ids(ids []cc.StringID) {
sort.Slice(ids, func(i, j int) bool {
return ids[i] < ids[j]
})
}
func cc_type_to_struct_member_type(t cc.Type) (m x64dbg.StructMemberType) {
var s string
var arrsize int32 = 1
var array bool
loop:
for t != nil {
if t.Name().String() != "" {
s = t.Name().String() + s
break
}
switch t.Kind() {
case cc.Ptr:
s = "*" + s
case cc.Array:
array = true
arrsize *= int32(t.Len())
case cc.Function:
s = "void*" + s
break loop
default:
s = t.Kind().String() + s
break loop
}
t = t.Elem()
}
if array {
m.ArraySize = arrsize
}
m.Offset = -1
m.Type = s
return
}
func cc_type_to_typedef(t cc.Type) (m x64dbg.Type) {
var s string
var arrsize int32 = 1
var array bool
loop:
for t != nil {
if t.Name().String() != "" && t.Kind() != cc.Enum {
s = t.Name().String() + s
break
}
switch t.Kind() {
case cc.Enum:
s = t.EnumType().String() + s
break loop
case cc.Ptr:
s = "*" + s
case cc.Array:
array = true
arrsize *= int32(t.Len())
case cc.Function:
s = "void*" + s
default:
s = t.Kind().String() + s
break loop
}
t = t.Elem()
}
if array {
m.ArraySize = arrsize
}
m.Type = s
return
}
// parses the C headers and generates a matching x64dbg types.json file
func (profile *Profile) generate_x64dbg_types() (err error) {
// parse C headers
var cc_config cc.Config
cc_config.ABI, err = cc.NewABI("windows", "386")
if err != nil {
panic(err)
}
cc_include_paths := []string{
filepath.Join(profile.Directory, "include"),
}
cc_system_include_paths := []string{
filepath.Join("go", "profile", "include"),
}
cc_sources := []cc.Source{
cc.Source{
Name: filepath.Join(profile.Directory, "include", "main.h"),
},
}
var ast *cc.AST
ast, err = cc.Translate(&cc_config, cc_include_paths, cc_system_include_paths, cc_sources)
if err != nil {
return
}
var x64_types x64dbg.Types
// Parse integer types
var scope_ids []cc.StringID
for name := range ast.Scope {
scope_ids = append(scope_ids, name)
}
sort_string_ids(scope_ids)
// these types needed by the C parser can't be included in x64dbg json
ignore_types := []string{
"int8_t",
"int16_t",
"int32_t",
"int64_t",
"uint8_t",
"uint16_t",
"uint32_t",
"uint64_t",
"bool",
}
for _, scope_id := range scope_ids {
scope := ast.Scope[scope_id]
for _, node := range scope {
if declarator, ok := node.(*cc.Declarator); ok {
if declarator.IsTypedefName {
if declarator.Type().Kind() != cc.Struct {
var x64_type x64dbg.Type = cc_type_to_typedef(declarator.Type())
x64_type.Name = scope_id.String()
if !slices.Contains(ignore_types, x64_type.Name) {
x64_types.Types = append(x64_types.Types, x64_type)
}
}
}
}
}
}
var struct_names []cc.StringID
for struct_name := range ast.StructTypes {
struct_names = append(struct_names, struct_name)
}
sort.Slice(struct_names, func(i, j int) bool {
return struct_names[i] < struct_names[j]
})
for _, struct_name := range struct_names {
struct_type := ast.StructTypes[struct_name]
var x64_struct x64dbg.StructType
x64_struct.Name = struct_name.String()
for i := range struct_type.NumField() {
struct_member := struct_type.FieldByIndex([]int{i})
// If struct member is a union
if struct_member.Type().Kind() == cc.Union {
union_member_name := struct_member.Name().String()
if union_member_name == "" {
// union is anonymous
union_member_name = fmt.Sprintf("%04d", struct_member.Offset())
}
union_type_name := fmt.Sprintf("%s__%s", struct_name.String(), union_member_name)
var x64_union x64dbg.UnionType
x64_union.Name = union_type_name
for i := range struct_member.Type().NumField() {
union_field := struct_member.Type().FieldByIndex([]int{i})
var x64_union_member x64dbg.Type = cc_type_to_typedef(union_field.Type())
x64_union_member.Name = union_field.Name().String()
x64_union.Members = append(x64_union.Members, x64_union_member)
}
x64_types.Unions = append(x64_types.Unions, x64_union)
x64_struct_member := x64dbg.StructMemberType{}
x64_struct_member.Type = union_type_name
x64_struct_member.Name = struct_member.Name().String()
x64_struct_member.Offset = int32(struct_member.Offset())
x64_struct.Members = append(x64_struct.Members, x64_struct_member)
} else {
x64_struct_member := cc_type_to_struct_member_type(struct_member.Type())
x64_struct_member.Name = struct_member.Name().String()
x64_struct_member.Offset = int32(struct_member.Offset())
x64_struct.Members = append(x64_struct.Members, x64_struct_member)
}
}
x64_types.Structs = append(x64_types.Structs, x64_struct)
}
types_file_path := filepath.Join(profile.Directory, "x32dbg", "types.json")
err = x64dbg.SaveTypes(types_file_path, &x64_types)
if err != nil {
return
}
fmt.Println("types generated!", types_file_path)
return
}

View file

@ -1,29 +1,33 @@
package symfile
import (
"slices"
"sort"
)
// Most tables are reasonably-sized and can be kept in memory
type InMemoryTable struct {
Entries []Entry
}
func (t *InMemoryTable) Insert(entry *Entry) (err error) {
i := sort.Search(len(t.Entries), func(i int) bool {
return t.Entries[i].StartAddress >= entry.StartAddress
})
if i < len(t.Entries) {
t.Entries = slices.Insert(t.Entries, i, *entry)
} else {
t.Entries = append(t.Entries, *entry)
}
return
}
func (t *InMemoryTable) Len() int {
return len(t.Entries)
}
package symfile
import (
"slices"
"sort"
)
// Most tables are reasonably-sized and can be kept in memory
type InMemoryTable struct {
Entries []Entry
}
func (t *InMemoryTable) Insert(entry *Entry) (err error) {
i := sort.Search(len(t.Entries), func(i int) bool {
return t.Entries[i].StartAddress >= entry.StartAddress
})
if i < len(t.Entries) {
t.Entries = slices.Insert(t.Entries, i, *entry)
} else {
t.Entries = append(t.Entries, *entry)
}
return
}
func (t *InMemoryTable) Len() int {
return len(t.Entries)
}
func NewInMemoryTable() *InMemoryTable {
return new(InMemoryTable)
}

View file

@ -1,44 +1,43 @@
package symfile
import (
"io"
)
// What kind of Entry is this?
type EntryKind uint8
const (
// Something that can be executed
Function EntryKind = 'f'
// Something that is read or written to
DataLabel EntryKind = 'l'
)
var (
valid_kinds = []EntryKind{Function, DataLabel}
)
// An entry in the table
type Entry struct {
// Undecorated, raw name
Name string
// Offset to the start of the function or data
StartAddress uint64
// What kind of Entry is this?
Kind EntryKind
// Any table entry can have a comment after a ';' column
Comment string
// Attributes
// end=AABBCCEEDD
EndAddress uint64
}
type Table interface {
Insert(entry *Entry) (err error)
// Find() (iter func() (entry *Entry, err error))
}
func Load(table Table, text io.Reader) (err error) {
err = load(text, table)
return
}
package symfile
import (
"io"
)
// What kind of Entry is this?
type EntryKind uint8
const (
// Something that can be executed
Function EntryKind = 'f'
// Something that is read or written to
DataLabel EntryKind = 'l'
)
var (
valid_kinds = []EntryKind{Function, DataLabel}
)
// An entry in the table
type Entry struct {
// Undecorated, raw name
Name string
// Offset to the start of the function or data
StartAddress uint64
// What kind of Entry is this?
Kind EntryKind
// Any table entry can have a comment after a ';' column
Comment string
// Attributes
// end=AABBCCEEDD
EndAddress uint64
}
type Table interface {
Insert(entry *Entry) (err error)
}
func Load(table Table, text io.Reader) (err error) {
err = load(text, table)
return
}

View file

@ -1,91 +1,77 @@
package x64dbg
import (
"encoding/json"
"io"
"os"
"github.com/pierrec/lz4/v4"
)
type Function struct {
Manual bool `json:"manual,omitempty"`
Start string `json:"start,omitempty"`
End string `json:"end,omitempty"`
Module string `json:"module,omitempty"`
InstructionCount string `json:"icount,omitempty"`
Parent string `json:"parent,omitempty"`
}
type Comment struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Text string `json:"text,omitempty"`
Address string `json:"address,omitempty"`
}
type Label struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Text string `json:"text,omitempty"`
Address string `json:"address,omitempty"`
}
type Bookmark struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Address string `json:"address,omitempty"`
}
type Breakpoint struct {
Address string `json:"address,omitempty"`
CommandText string `json:"commandText,omitempty"`
Enabled bool `json:"enabled,omitempty"`
FastResume string `json:"fastResume,omitempty"`
OldBytes string `json:"oldbytes,omitempty"`
Type string `json:"type,omitempty"`
Module string `json:"module,omitempty"`
TitanType string `json:"titantype,omitempty"`
Name string `json:"name,omitempty"`
BreakCondition string `json:"breakCondition,omitempty"`
LogText string `json:"logText,omitempty"`
LogCondition string `json:"logCondition,omitempty"`
Silent string `json:"silent,omitempty"`
CommandCondition string `json:"commandCondition,omitempty"`
}
type Database struct {
Functions []Function `json:"functions,omitempty"`
Comments []Comment `json:"comments,omitempty"`
Labels []Label `json:"labels,omitempty"`
Bookmarks []Bookmark `json:"bookmarks,omitempty"`
Breakpoints []Breakpoint `json:"breakpoints,omitempty"`
}
func SaveDatabase(name string, database *Database, compress bool) (err error) {
var file *os.File
file, err = os.Create(name)
if err != nil {
return
}
var writecloser io.WriteCloser = file
if compress {
lz4_writer := lz4.NewWriter(file)
writecloser = lz4_writer
}
e := json.NewEncoder(writecloser)
e.SetIndent("", " ")
if err = e.Encode(database); err != nil {
return
}
if compress {
writecloser.Close()
}
err = file.Close()
return
}
package x64dbg
import (
"encoding/json"
"os"
)
type Function struct {
Manual bool `json:"manual,omitempty"`
Start string `json:"start,omitempty"`
End string `json:"end,omitempty"`
Module string `json:"module,omitempty"`
InstructionCount string `json:"icount,omitempty"`
Parent string `json:"parent,omitempty"`
}
type Comment struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Text string `json:"text,omitempty"`
Address string `json:"address,omitempty"`
}
type Label struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Text string `json:"text,omitempty"`
Address string `json:"address,omitempty"`
}
type Bookmark struct {
Manual bool `json:"manual,omitempty"`
Module string `json:"module,omitempty"`
Address string `json:"address,omitempty"`
}
type Breakpoint struct {
Address string `json:"address,omitempty"`
CommandText string `json:"commandText,omitempty"`
Enabled bool `json:"enabled,omitempty"`
FastResume string `json:"fastResume,omitempty"`
OldBytes string `json:"oldbytes,omitempty"`
Type string `json:"type,omitempty"`
Module string `json:"module,omitempty"`
TitanType string `json:"titantype,omitempty"`
Name string `json:"name,omitempty"`
BreakCondition string `json:"breakCondition,omitempty"`
LogText string `json:"logText,omitempty"`
LogCondition string `json:"logCondition,omitempty"`
Silent string `json:"silent,omitempty"`
CommandCondition string `json:"commandCondition,omitempty"`
}
type Database struct {
Functions []Function `json:"functions,omitempty"`
Comments []Comment `json:"comments,omitempty"`
Labels []Label `json:"labels,omitempty"`
Bookmarks []Bookmark `json:"bookmarks,omitempty"`
Breakpoints []Breakpoint `json:"breakpoints,omitempty"`
}
func SaveDatabase(name string, database *Database) (err error) {
var file *os.File
file, err = os.Create(name)
if err != nil {
return
}
e := json.NewEncoder(file)
e.SetIndent("", " ")
if err = e.Encode(database); err != nil {
return
}
err = file.Close()
return
}

61
go/x64dbg/types.go Normal file
View file

@ -0,0 +1,61 @@
package x64dbg
import (
"encoding/json"
"os"
)
type Type struct {
Type string `json:"type"`
Name string `json:"name"`
ArraySize int32 `json:"arrsize,omitempty"`
}
type StructMemberType struct {
Type string `json:"type"`
Name string `json:"name"`
ArraySize int32 `json:"arrsize,omitempty"`
Offset int32 `json:"offset,omitempty"`
}
type StructType struct {
Name string `json:"name"`
Members []StructMemberType `json:"members,omitempty"`
}
type UnionType struct {
Name string `json:"name"`
Members []Type `json:"members,omitempty"`
}
type FunctionType struct {
ReturnType string `json:"rettype"`
CallConvention string `json:"callconv"`
NoReturn bool `json:"noreturn"`
Name string `json:"name"`
Arguments []Type `json:"arguments,omitempty"`
}
type Types struct {
Types []Type `json:"types,omitempty"`
Structs []StructType `json:"structs,omitempty"`
Unions []UnionType `json:"unions,omitempty"`
Functions []FunctionType `json:"functions,omitempty"`
}
func SaveTypes(name string, types *Types) (err error) {
var file *os.File
file, err = os.Create(name)
if err != nil {
return
}
e := json.NewEncoder(file)
e.SetIndent("", " ")
if err = e.Encode(types); err != nil {
return
}
err = file.Close()
return
}

View file

@ -1,11 +1,11 @@
#!/usr/bin/env bash
# this script just collects symbols into one file for convenience
if [ $# -eq 0 ]
then
echo "Select a version to use"
exit 1
fi
awk 1 $1/symbol/*/*.sym | sort -k2 -t' ' > $1/symbol/main.sym
#!/usr/bin/env bash
# this script just collects symbols into one file for convenience
if [ $# -eq 0 ]
then
echo "Select a version to use"
exit 1
fi
awk 1 $1/symbol/*/*.sym | sort -k2 -t' ' > $1/symbol/main.sym