mirror of
https://github.com/thunderbrewhq/binana.git
synced 2025-12-12 09:52:28 +00:00
feat(binana): add check command for profiles
This commit is contained in:
parent
b5ddafb89a
commit
ebf88595d9
11 changed files with 151 additions and 39 deletions
97
go/cmd/binana/cmd/check.go
Normal file
97
go/cmd/binana/cmd/check.go
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/thunderbrewhq/binana/go/profile"
|
||||
"github.com/thunderbrewhq/binana/go/symfile"
|
||||
)
|
||||
|
||||
type check_params struct {
|
||||
ProfileName string
|
||||
Constructors bool
|
||||
Bounds bool
|
||||
}
|
||||
|
||||
func check(params *check_params) {
|
||||
p, err := profile.Open(params.ProfileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
named_function_count := uint64(0)
|
||||
|
||||
warnings := uint64(0)
|
||||
|
||||
warn := func(s *symfile.Entry, f string, args ...any) {
|
||||
warnings++
|
||||
color.Set(color.FgRed)
|
||||
fmt.Printf(" warning: ")
|
||||
color.Unset()
|
||||
fmt.Printf("in line %d: (%s): ", s.LineNumber, s.Name)
|
||||
fmt.Printf(f, args...)
|
||||
}
|
||||
|
||||
for _, s := range p.SymbolTable.Entries {
|
||||
sn := s.Name
|
||||
|
||||
if s.Kind == symfile.Function {
|
||||
named_function_count++
|
||||
|
||||
if params.Constructors {
|
||||
//
|
||||
b, a, found := strings.Cut(sn, "__")
|
||||
if found {
|
||||
if b == a {
|
||||
warn(&s, "this style of naming a constructor function is preferred: ClassName__constructor\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if params.Bounds {
|
||||
if s.EndAddress == 0 {
|
||||
warn(&s, "does not have an end address\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.Info.FunctionCount != 0 {
|
||||
ratio := float64(named_function_count) / float64(p.Info.FunctionCount)
|
||||
fmt.Printf("%d out of %d functions named (%f%%)\n", named_function_count, p.Info.FunctionCount, ratio*100.0)
|
||||
fmt.Printf("%d warnings generated\n", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
func check_run(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 1 {
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
f := cmd.Flags()
|
||||
var params check_params
|
||||
params.ProfileName = args[0]
|
||||
|
||||
var err error
|
||||
|
||||
params.Constructors, err = f.GetBool("constructors")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
params.Bounds, err = f.GetBool("bounds")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
check(¶ms)
|
||||
}
|
||||
|
||||
var check_cmd = cobra.Command{
|
||||
Use: "check profile",
|
||||
Short: "check a profile for correctness",
|
||||
Run: check_run,
|
||||
}
|
||||
|
|
@ -81,12 +81,12 @@ func format_symbols(in io.Reader, out io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
func format_symbols_func(cmd *cobra.Command, args []string) {
|
||||
func format_symbols_run(cmd *cobra.Command, args []string) {
|
||||
format_symbols(os.Stdin, os.Stdout)
|
||||
}
|
||||
|
||||
var format_symbols_cmd = &cobra.Command{
|
||||
var format_symbols_cmd = cobra.Command{
|
||||
Use: "format-symbols",
|
||||
Short: "format symbols from stdin",
|
||||
Run: format_symbols_func,
|
||||
Run: format_symbols_run,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,7 @@ import (
|
|||
"github.com/thunderbrewhq/binana/go/profile"
|
||||
)
|
||||
|
||||
var generate = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Convert source files into various tool formats",
|
||||
Run: generate_func,
|
||||
}
|
||||
|
||||
func generate_func(cmd *cobra.Command, args []string) {
|
||||
func generate_run(cmd *cobra.Command, args []string) {
|
||||
compress, err := cmd.Flags().GetBool("compress")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -35,3 +29,9 @@ func generate_func(cmd *cobra.Command, args []string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
var generate_cmd = cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Convert source files into various tool formats",
|
||||
Run: generate_run,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
var root = cobra.Command{
|
||||
Use: "binana",
|
||||
Short: "Binana helper tool",
|
||||
}
|
||||
|
|
@ -18,27 +18,21 @@ var rootCmd = &cobra.Command{
|
|||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
err := root.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
generate_cmd.Flags().StringP("profile", "p", "3.3.5a", "the game profile")
|
||||
generate_cmd.Flags().BoolP("compress", "c", true, "enable/disable compression of the x64dbg database file")
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.binana.yaml)")
|
||||
check_cmd.Flags().Bool("bounds", false, "check for bad function boundaries")
|
||||
check_cmd.Flags().Bool("constructors", false, "check for outdated class constructor names")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
|
||||
generate.Flags().StringP("profile", "p", "3.3.5a", "the game profile")
|
||||
generate.Flags().BoolP("compress", "c", true, "enable/disable compression of the x64dbg database file")
|
||||
|
||||
rootCmd.AddCommand(generate)
|
||||
rootCmd.AddCommand(format_symbols_cmd)
|
||||
rootCmd.AddCommand(x64dbg_typesort)
|
||||
root.AddCommand(&generate_cmd)
|
||||
root.AddCommand(&format_symbols_cmd)
|
||||
root.AddCommand(&x64dbg_typesort_cmd)
|
||||
root.AddCommand(&check_cmd)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import (
|
|||
"github.com/thunderbrewhq/binana/go/x64dbg"
|
||||
)
|
||||
|
||||
var x64dbg_typesort = &cobra.Command{
|
||||
var x64dbg_typesort_cmd = cobra.Command{
|
||||
Use: "x64dbg-typesort [types.json file]",
|
||||
Short: "sort a x64dbg types file",
|
||||
Run: x64dbg_typesort_func,
|
||||
Run: x64dbg_typesort_run,
|
||||
}
|
||||
|
||||
func x64dbg_typesort_func(cmd *cobra.Command, args []string) {
|
||||
func x64dbg_typesort_run(cmd *cobra.Command, args []string) {
|
||||
types, err := x64dbg.LoadTypes(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
|||
|
|
@ -23,17 +23,19 @@ var (
|
|||
)
|
||||
|
||||
type info_schema struct {
|
||||
OS string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
ModuleName string `json:"module_name"`
|
||||
ModuleBase string `json:"module_base"`
|
||||
OS string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
ModuleName string `json:"module_name"`
|
||||
ModuleBase string `json:"module_base"`
|
||||
FunctionCount uint64 `json:"function_count"`
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
OS string
|
||||
Arch string
|
||||
ModuleName string
|
||||
ModuleBase uint64
|
||||
OS string
|
||||
Arch string
|
||||
ModuleName string
|
||||
ModuleBase uint64
|
||||
FunctionCount uint64
|
||||
}
|
||||
|
||||
func read_info(filename string, info *Info) (err error) {
|
||||
|
|
@ -68,5 +70,7 @@ func read_info(filename string, info *Info) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
info.FunctionCount = is.FunctionCount
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func (profile *Profile) generate_x64dbg_database(compress bool) (err error) {
|
|||
relative_end_address -= 1
|
||||
}
|
||||
|
||||
if relative_end_address < relative_start_address || relative_end_address-relative_start_address >= 10000 {
|
||||
if relative_end_address < relative_start_address || relative_end_address-relative_start_address >= 50000 {
|
||||
fmt.Printf("Strange symbol %s %08x %08x (offset %d)\n", entry.Name, relative_start_address, relative_end_address, relative_end_address-relative_start_address)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const min_columns = 3
|
|||
type loader struct {
|
||||
input *bufio.Reader
|
||||
table Table
|
||||
line_number int
|
||||
line_number uint64
|
||||
}
|
||||
|
||||
func (l *loader) read_line() (line string, err error) {
|
||||
|
|
@ -32,6 +32,7 @@ func (l *loader) parse_line(line string) (err error) {
|
|||
err = fmt.Errorf("%w: line %d", err, l.line_number)
|
||||
return
|
||||
}
|
||||
entry.LineNumber = l.line_number
|
||||
|
||||
err = l.table.Insert(&entry)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ var (
|
|||
|
||||
// An entry in the table
|
||||
type Entry struct {
|
||||
LineNumber uint64
|
||||
// Undecorated, raw name
|
||||
Name string
|
||||
// Offset to the start of the function or data
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue