NCPrePatcher 0.2.0-x86_64-darwin-24 → 0.3.1-x86_64-darwin-24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fb94ffb2c12a0199472ef3ce47b57a99a8291097895a8ef301ba638896e29a4
4
- data.tar.gz: 969268c9be992b5db723db20afcece52db9e072d548743ce5554321aeaddb1e6
3
+ metadata.gz: a118d0e7ead9b035c258c26888fff3e29e6689442300c15ca51436f7c7d48b21
4
+ data.tar.gz: 4d16a441aa41a835254c42d31a47a67b3dad11ad1ebdf6402b0683970470420c
5
5
  SHA512:
6
- metadata.gz: d9b4a959ced1bf841c3a749c8370c24bc36a092835352e786c35f43424787fe572a26eb23bce7057f1e24e9dad042461325ec1d1e38ecc39a6acb2519fb21b41
7
- data.tar.gz: 28d878f55a86668301991f3544d62e4d1eedb34c9d4a302acb4583bfbb79d02baf9350db0fee90a2fec57a5d43316b6e1eadb3ce6d5062f79ecd9bc2cda0eb9b
6
+ metadata.gz: a4dfd40d3405b3e62951c6c78812462ed87d213ad1b542857c92a22738edb5c290d195a7159aa8b6557df319c30361b458ca88621f336cb5bcefee4e73f45fd6
7
+ data.tar.gz: 75b1a03e961b34d6d1341e05a971f315bc0a4b792516d7a54b0cb05228d9b5373c0f404e487fa1a94d359aded322f2ee0812a4130a70a68808bf042684328ab9
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # NCPrePatcher
2
2
 
3
- A preprocessor for [NCPatcher](https://github.com/TheGameratorT/NCPatcher) with access to your NDS ROM and a disassembler.
3
+ A preprocessor for [NCPatcher](https://github.com/TheGameratorT/NCPatcher) with access to your NDS ROM, a disassembler, an assembler, and an emulator.
4
4
 
5
5
  ## Installation
6
6
 
@@ -47,13 +47,19 @@ ncpp --help
47
47
  - Ruby
48
48
  - CMake and a modern C++ compiler
49
49
  - Rust and Cargo
50
+ - vcpkg
50
51
 
51
- To build the required native libraries, go to /ext/ and run:
52
+ To build the nitro and unarm native libraries, go to /ext/ and run:
52
53
  ```console
53
54
  ruby build.rb
54
55
  ```
55
56
 
56
- Then go back to the base directory and run:
57
+ To build the unicorn and keystone native libraries run:
58
+ ```console
59
+ vcpkg install unicorn keystone --triplet [your platform]-dynamic
60
+ ```
61
+
62
+ Move the built binaries to `lib/unicorn` and `lib/keystone` respectively, and finally, go back to the base directory and run:
57
63
  ```console
58
64
  gem build ncpp.gemspec
59
65
  ```
@@ -63,4 +69,6 @@ gem build ncpp.gemspec
63
69
  - Code from NCPatcher used by the **nitro** library
64
70
  - [unarm](https://github.com/AetiasHax/unarm) used for disassembling
65
71
  - [Ruby-FFI](https://github.com/ffi/ffi) used for binding the above libraries to Ruby
66
- - [Parslet](https://github.com/kschiess/parslet) used for parsing the DSL
72
+ - [Parslet](https://github.com/kschiess/parslet) used for parsing the DSL
73
+ - [Unicorn](https://github.com/unicorn-engine/unicorn/tree/master) used for emulating
74
+ - [Keystone](https://github.com/keystone-engine/keystone/tree/master) used for assembling
@@ -0,0 +1,7 @@
1
+ # For Keystone Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.rb]
2
+
3
+ module Keystone
4
+ KS_ERR_ASM_ARM_INVALIDOPERAND = 512
5
+ KS_ERR_ASM_ARM_MISSINGFEATURE = 513
6
+ KS_ERR_ASM_ARM_MNEMONICFAIL = 514
7
+ end
Binary file
@@ -0,0 +1,76 @@
1
+ require 'ffi'
2
+
3
+ require_relative 'arm_const.rb'
4
+ require_relative 'keystone_const.rb'
5
+ require_relative 'version.rb'
6
+
7
+ module KeystoneBind
8
+ extend FFI::Library
9
+ ffi_lib [
10
+ File.expand_path("keystone", __dir__),
11
+ File.expand_path("keystone.dylib", __dir__),
12
+ File.expand_path("keystone.so", __dir__),
13
+ ]
14
+
15
+ typedef :pointer, :ks_engine
16
+ typedef :pointer, :ks_engine_handle
17
+ typedef :uint, :ks_arch
18
+ typedef :uint, :ks_err
19
+ typedef :uint, :ks_opt_type
20
+
21
+ attach_function :ks_version, [:pointer, :pointer], :uint
22
+ attach_function :ks_arch_supported, [:ks_arch], :bool
23
+ attach_function :ks_open, [:ks_arch, :int, :ks_engine_handle], :ks_err
24
+ attach_function :ks_close, [:ks_engine], :ks_err
25
+ attach_function :ks_errno, [:ks_engine], :ks_err
26
+ attach_function :ks_strerror, [:ks_err], :string
27
+ attach_function :ks_option, [:ks_engine, :ks_opt_type, :size_t], :ks_err
28
+ attach_function :ks_asm, [:ks_engine, :string, :uint64, :pointer, :pointer, :pointer], :int
29
+ attach_function :ks_free, [:pointer], :void
30
+ end
31
+
32
+ module Keystone
33
+ extend KeystoneBind
34
+
35
+ def self.major_version
36
+ ks_version(nil, nil)
37
+ end
38
+
39
+ def self.arch_supported?(ks_arch)
40
+ ks_arch_supported(ks_arch)
41
+ end
42
+
43
+ class Assembler
44
+ include KeystoneBind
45
+
46
+ def initialize(arch: KS_ARCH_ARM, mode: KS_MODE_ARM)
47
+
48
+ FFI::MemoryPointer.new(:pointer,1) do |ptr|
49
+ safe_call(:ks_open, arch, mode, ptr)
50
+ @engine = FFI::AutoPointer.new(ptr.read_pointer, method(:ks_close))
51
+ end
52
+ end
53
+
54
+ def assemble(asm_str, addr: 0)
55
+ encoding_ptr = FFI::MemoryPointer.new(:pointer)
56
+ encoding_size = FFI::MemoryPointer.new(:size_t)
57
+ stat_count = FFI::MemoryPointer.new(:size_t)
58
+ safe_call(:ks_asm, @engine, asm_str, addr, encoding_ptr, encoding_size, stat_count)
59
+ encoded_bytes = encoding_ptr.read_pointer.read_array_of_uint8(encoding_size.read_uint)
60
+ ks_free(encoding_ptr.read_pointer)
61
+ encoded_bytes.pack('C*')
62
+ end
63
+
64
+ def set_option(ks_opt_type, value)
65
+ safe_call(:ks_option, @engine, ks_opt_type, value)
66
+ end
67
+
68
+ private
69
+ def safe_call(meth_sym, *args)
70
+ err = send(meth_sym, *args)
71
+ raise "Error from #{meth_sym}: #{ks_strerror(err)}" if err != KS_ERR_OK
72
+ end
73
+ end
74
+ end
75
+
76
+ Ks = Keystone
@@ -0,0 +1,97 @@
1
+ # For Keystone Engine. AUTO-GENERATED FILE, DO NOT EDIT [keystone_const.rb]
2
+
3
+ module Keystone
4
+ KS_API_MAJOR = 0
5
+ KS_API_MINOR = 9
6
+ KS_VERSION_MAJOR = 0
7
+ KS_VERSION_MINOR = 9
8
+ KS_VERSION_EXTRA = 2
9
+ KS_ARCH_ARM = 1
10
+ KS_ARCH_ARM64 = 2
11
+ KS_ARCH_MIPS = 3
12
+ KS_ARCH_X86 = 4
13
+ KS_ARCH_PPC = 5
14
+ KS_ARCH_SPARC = 6
15
+ KS_ARCH_SYSTEMZ = 7
16
+ KS_ARCH_HEXAGON = 8
17
+ KS_ARCH_EVM = 9
18
+ KS_ARCH_RISCV = 10
19
+ KS_ARCH_MAX = 11
20
+ KS_MODE_LITTLE_ENDIAN = 0
21
+ KS_MODE_BIG_ENDIAN = 1073741824
22
+ KS_MODE_ARM = 1
23
+ KS_MODE_THUMB = 16
24
+ KS_MODE_V8 = 64
25
+ KS_MODE_MICRO = 16
26
+ KS_MODE_MIPS3 = 32
27
+ KS_MODE_MIPS32R6 = 64
28
+ KS_MODE_MIPS32 = 4
29
+ KS_MODE_MIPS64 = 8
30
+ KS_MODE_16 = 2
31
+ KS_MODE_32 = 4
32
+ KS_MODE_64 = 8
33
+ KS_MODE_PPC32 = 4
34
+ KS_MODE_PPC64 = 8
35
+ KS_MODE_QPX = 16
36
+ KS_MODE_RISCV32 = 4
37
+ KS_MODE_RISCV64 = 8
38
+ KS_MODE_SPARC32 = 4
39
+ KS_MODE_SPARC64 = 8
40
+ KS_MODE_V9 = 16
41
+ KS_ERR_ASM = 128
42
+ KS_ERR_ASM_ARCH = 512
43
+ KS_ERR_OK = 0
44
+ KS_ERR_NOMEM = 1
45
+ KS_ERR_ARCH = 2
46
+ KS_ERR_HANDLE = 3
47
+ KS_ERR_MODE = 4
48
+ KS_ERR_VERSION = 5
49
+ KS_ERR_OPT_INVALID = 6
50
+ KS_ERR_ASM_EXPR_TOKEN = 128
51
+ KS_ERR_ASM_DIRECTIVE_VALUE_RANGE = 129
52
+ KS_ERR_ASM_DIRECTIVE_ID = 130
53
+ KS_ERR_ASM_DIRECTIVE_TOKEN = 131
54
+ KS_ERR_ASM_DIRECTIVE_STR = 132
55
+ KS_ERR_ASM_DIRECTIVE_COMMA = 133
56
+ KS_ERR_ASM_DIRECTIVE_RELOC_NAME = 134
57
+ KS_ERR_ASM_DIRECTIVE_RELOC_TOKEN = 135
58
+ KS_ERR_ASM_DIRECTIVE_FPOINT = 136
59
+ KS_ERR_ASM_DIRECTIVE_UNKNOWN = 137
60
+ KS_ERR_ASM_DIRECTIVE_EQU = 138
61
+ KS_ERR_ASM_DIRECTIVE_INVALID = 139
62
+ KS_ERR_ASM_VARIANT_INVALID = 140
63
+ KS_ERR_ASM_EXPR_BRACKET = 141
64
+ KS_ERR_ASM_SYMBOL_MODIFIER = 142
65
+ KS_ERR_ASM_SYMBOL_REDEFINED = 143
66
+ KS_ERR_ASM_SYMBOL_MISSING = 144
67
+ KS_ERR_ASM_RPAREN = 145
68
+ KS_ERR_ASM_STAT_TOKEN = 146
69
+ KS_ERR_ASM_UNSUPPORTED = 147
70
+ KS_ERR_ASM_MACRO_TOKEN = 148
71
+ KS_ERR_ASM_MACRO_PAREN = 149
72
+ KS_ERR_ASM_MACRO_EQU = 150
73
+ KS_ERR_ASM_MACRO_ARGS = 151
74
+ KS_ERR_ASM_MACRO_LEVELS_EXCEED = 152
75
+ KS_ERR_ASM_MACRO_STR = 153
76
+ KS_ERR_ASM_MACRO_INVALID = 154
77
+ KS_ERR_ASM_ESC_BACKSLASH = 155
78
+ KS_ERR_ASM_ESC_OCTAL = 156
79
+ KS_ERR_ASM_ESC_SEQUENCE = 157
80
+ KS_ERR_ASM_ESC_STR = 158
81
+ KS_ERR_ASM_TOKEN_INVALID = 159
82
+ KS_ERR_ASM_INSN_UNSUPPORTED = 160
83
+ KS_ERR_ASM_FIXUP_INVALID = 161
84
+ KS_ERR_ASM_LABEL_INVALID = 162
85
+ KS_ERR_ASM_FRAGMENT_INVALID = 163
86
+ KS_ERR_ASM_INVALIDOPERAND = 512
87
+ KS_ERR_ASM_MISSINGFEATURE = 513
88
+ KS_ERR_ASM_MNEMONICFAIL = 514
89
+ KS_OPT_SYNTAX = 1
90
+ KS_OPT_SYM_RESOLVER = 2
91
+ KS_OPT_SYNTAX_INTEL = 1
92
+ KS_OPT_SYNTAX_ATT = 2
93
+ KS_OPT_SYNTAX_NASM = 4
94
+ KS_OPT_SYNTAX_MASM = 8
95
+ KS_OPT_SYNTAX_GAS = 16
96
+ KS_OPT_SYNTAX_RADIX16 = 32
97
+ end
@@ -0,0 +1,3 @@
1
+ module KeystoneEngine
2
+ VERSION = '0.9.2'
3
+ end
data/lib/ncpp/commands.rb CHANGED
@@ -206,6 +206,9 @@ module NCPP
206
206
  hex: ->(i) { Utils.integer_check(i,'hex'); i.to_hex }.returns(String)
207
207
  .describe('Returns a hexadecimal representation of the given Integer.'),
208
208
 
209
+ ord: ->(s) { s.ord }.returns(Integer)
210
+ .describe('Gets the Integer ordinal of the first character in the given String.'),
211
+
209
212
  string: ->(x) { String(x) }.returns(String)
210
213
  .describe('Gets the given argument as a String.'),
211
214
 
@@ -587,6 +590,7 @@ module NCPP
587
590
  exp: ->(n) { Math.exp(n) }.returns(Float).describe('Gets e raised to the power of the given number.'),
588
591
  log: ->(n) { Math.log(n) }.returns(Float).describe('Gets the base logarithm of the given number.'),
589
592
  sqrt: ->(n) { Math.sqrt(n) }.returns(Float).describe('Gets the square root of the given number.'),
593
+ round: ->(f, n_digits=0) { f.round(n_digits) }.returns(Numeric),
590
594
  clamp: ->(n, min,max=nil) { n.clamp(min,max) }.returns(Numeric)
591
595
  .describe('Clamps number between given min and max values.'),
592
596
 
@@ -644,7 +648,7 @@ module NCPP
644
648
  "the original ASM with the immediate swapped to the value given."),
645
649
 
646
650
  repl_array: ->(loc, ov, dtype, arr) { Utils.gen_repl_array(loc,ov,dtype,arr) }.returns(String),
647
-
651
+
648
652
  repl_u64_array: ->(loc,ov_or_arr,arr=nil) { Utils.gen_repl_type_array(loc, ov_or_arr, :u64, arr) }.returns(String),
649
653
  repl_s64_array: ->(loc,ov_or_arr,arr=nil) { Utils.gen_repl_type_array(loc, ov_or_arr, :s64, arr) }.returns(String),
650
654
  repl_u32_array: ->(loc,ov_or_arr,arr=nil) { Utils.gen_repl_type_array(loc, ov_or_arr, :u32, arr) }.returns(String),
@@ -677,11 +681,15 @@ module NCPP
677
681
  get_signed_byte: ->(addr,ov=nil) { Utils.get_signed_byte(addr,ov) }.returns(Integer),
678
682
  get_cstring: ->(addr,ov=nil) { Utils.get_cstring(addr,ov) }.returns(String),
679
683
  get_array: ->(addr,ov,e_type_id,e_count=1) { Utils.get_array(addr,ov,e_type_id,e_count) }.returns(Array),
684
+ get_chars: ->(addr,ov, char_count) { Utils.get_array(addr,ov,Utils::DTYPE_IDS[:u8],char_count).map { it.chr } }
685
+ .returns(Array),
680
686
 
681
687
  get_c_array: ->(addr,ov,e_type_id,e_count=1) {
682
688
  Utils.to_c_array(Utils.get_array(addr,ov,e_type_id,e_count))
683
689
  }.returns(Array),
684
690
 
691
+ get_byte_str: ->(loc,ov,size) { Utils.get_byte_str(loc,ov,size) }.returns(String),
692
+
685
693
  find_first_branch_to: ->(branch_dest, start_loc,start_ov=nil) {
686
694
  Utils.find_branch_to(branch_dest, start_loc,start_ov)
687
695
  }.returns(Integer),
@@ -772,6 +780,14 @@ module NCPP
772
780
  s16: ->(n) { n.signed(16) }.returns(Integer).describe('Gets the given number as a signed 16-bit Integer.'),
773
781
  u8: ->(n) { n.unsigned(8) }.returns(Integer).describe('Gets the given number as an unsigned 8-bit Integer.'),
774
782
  s8: ->(n) { n.signed(8) }.returns(Integer).describe('Gets the given number as a signed 8-bit Integer.'),
783
+ char: ->(n) { n.unsigned(8).chr }.returns(String).describe('Gets the given number as an ASCII character.'),
784
+
785
+ sizeof: ->(dtype) { Utils::DTYPES[dtype][:size] }.returns(Integer),
786
+
787
+ f32: ->(n) { [n].pack('g').unpack('L>') }.returns(Integer),
788
+ f64: ->(n) { [n].pack('G').unpack('Q>') }.returns(Integer),
789
+ from_f32: ->(n) { [n].pack('L>').unpack('g')[0] }.returns(Float),
790
+ from_f64: ->(n) { [n].pack('Q>').unpack('G')[0] }.returns(Float),
775
791
 
776
792
  from_fx_deg: ->(fx_num) {
777
793
  Float(fx_num) / 0x10000 * 360
@@ -794,7 +810,36 @@ module NCPP
794
810
  from_gx_rgb: ->(n) { [(n >> 0) & 31, (n >> 5) & 31, (n >> 10) & 31] }.returns(Array)
795
811
  .describe('Unpacks the given RGB x1B5G5R5 value as an Array ([R,G,B]).'),
796
812
  from_gx_rgba: ->(n) { [(n >> 0) & 31, (n >> 5) & 31, (n >> 10) & 31, (n >> 15) & 1] }.returns(Array)
797
- .describe('Unpacks the given packed RGB A1B5G5R5 value as an Array ([R,G,B,A]).')
813
+ .describe('Unpacks the given packed RGB A1B5G5R5 value as an Array ([R,G,B,A]).'),
814
+
815
+ pack_u64_array: ->(arr) { arr.pack('Q*') }.returns(String),
816
+ pack_u32_array: ->(arr) { arr.pack('L*') }.returns(String),
817
+ pack_u16_array: ->(arr) { arr.pack('S*') }.returns(String),
818
+ pack_u8_array: ->(arr) { arr.pack('C*') }.returns(String),
819
+ pack_s64_array: ->(arr) { arr.pack('q*') }.returns(String),
820
+ pack_s32_array: ->(arr) { arr.pack('l*') }.returns(String),
821
+ pack_s16_array: ->(arr) { arr.pack('s*') }.returns(String),
822
+ pack_s8_array: ->(arr) { arr.pack('c*') }.returns(String),
823
+
824
+ unpack_u64_array: ->(byte_str) { byte_str.unpack('Q*') }.returns(Array),
825
+ unpack_u32_array: ->(byte_str) { byte_str.unpack('L*') }.returns(Array),
826
+ unpack_u16_array: ->(byte_str) { byte_str.unpack('S*') }.returns(Array),
827
+ unpack_u8_array: ->(byte_str) { byte_str.unpack('C*') }.returns(Array),
828
+ unpack_s64_array: ->(byte_str) { byte_str.unpack('q*') }.returns(Array),
829
+ unpack_s32_array: ->(byte_str) { byte_str.unpack('l*') }.returns(Array),
830
+ unpack_s16_array: ->(byte_str) { byte_str.unpack('s*') }.returns(Array),
831
+ unpack_s8_array: ->(byte_str) { byte_str.unpack('c*') }.returns(Array),
832
+
833
+ emulate_func: ->(loc,ov,*args) { Utils.emulate_func(loc,ov,*args) }.returns(Object).impure,
834
+ emu_get_reg: ->(reg_s) { $emu.read_reg(reg_s.to_sym) }.returns(Integer).impure,
835
+ emu_set_reg: ->(reg_s,val) { $emu.write_reg(reg_s.to_sym,val) }.impure,
836
+ emu_get_mem: ->(loc,size) { Utils.emu_get_mem(loc,size) }.returns(String).impure,
837
+ emu_set_mem: ->(loc,byte_str) { Utils.emu_set_mem(loc,byte_str) }.impure,
838
+ emu_load_ov: ->(ov_id) { $emu.load_overlay(ov_id) }.impure,
839
+ emu_reset: -> { $emu = Uc::Emu.new(); $emu.load_arm9 }.impure,
840
+
841
+ assemble_arm: ->(asm,addr=0) { Utils.assemble_arm(asm,addr:addr) }.returns(Integer),
842
+ assemble_thumb: ->(asm,addr=0) { Utils.assemble_thumb(asm,addr:addr) }.returns(Integer),
798
843
 
799
844
  },
800
845
 
@@ -839,6 +884,7 @@ module NCPP
839
884
  get_s8: :get_signed_byte,
840
885
  get_cstr: :get_cstring,
841
886
  disasm_ins: :disasm_arm_ins,
887
+ disasm: :disasm_arm_ins,
842
888
  disasm_hex_seq: :disasm_arm_hex_seq,
843
889
  disasm_hex_str: :disasm_arm_hex_seq,
844
890
  disasm_arm_hex_str: :disasm_arm_hex_seq,
@@ -876,7 +922,34 @@ module NCPP
876
922
  is_addr_in_ov: :is_address_in_overlay,
877
923
  is_addr_in_arm9: :is_address_in_arm9,
878
924
  is_addr_in_arm7: :is_address_in_arm7,
879
- find_hex_seq: :find_hex_bytes
925
+ find_hex_seq: :find_hex_bytes,
926
+ pack_u64_arr: :pack_u64_array,
927
+ pack_u32_arr: :pack_u32_array,
928
+ pack_u16_arr: :pack_u16_array,
929
+ pack_u8_arr: :pack_u8_array,
930
+ pack_s64_arr: :pack_s64_array,
931
+ pack_s32_arr: :pack_s32_array,
932
+ pack_s16_arr: :pack_s16_array,
933
+ pack_s8_arr: :pack_s8_array,
934
+ unpack_u64_arr: :unpack_u64_array,
935
+ unpack_u32_arr: :unpack_u32_array,
936
+ unpack_u16_arr: :unpack_u16_array,
937
+ unpack_u8_arr: :unpack_u8_array,
938
+ unpack_s64_arr: :unpack_s64_array,
939
+ unpack_s32_arr: :unpack_s32_array,
940
+ unpack_s16_arr: :unpack_s16_array,
941
+ unpack_s8_arr: :unpack_s8_array,
942
+ emulate_function: :emulate_func,
943
+ emu_call_func: :emulate_func,
944
+ emu_get_register: :emu_get_reg,
945
+ emu_set_register: :emu_set_reg,
946
+ emu_get_memory: :emu_get_mem,
947
+ emu_set_memory: :emu_set_mem,
948
+ emu_load_overlay: :emu_load_ov,
949
+ assemble: :assemble_arm,
950
+ assemble_ins: :assemble_arm,
951
+ assemble_arm_ins: :assemble_arm,
952
+ assemble_thumb_ins: :assemble_thumb
880
953
  }).freeze
881
954
 
882
955
 
@@ -170,7 +170,8 @@ module NCPP
170
170
  def: :define,
171
171
  desc: :describe,
172
172
  get_cmd_names: :get_command_names,
173
- get_var_names: :get_variable_names
173
+ get_var_names: :get_variable_names,
174
+ clear_cache: :invalidate_cache
174
175
  }).freeze
175
176
  end
176
177
 
data/lib/ncpp/utils.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require_relative '../nitro/nitro.rb'
2
2
  require_relative '../unarm/unarm.rb'
3
+ require_relative '../unicorn/unicorn.rb'
3
4
 
4
5
  require 'did_you_mean/jaro_winkler'
5
6
  require 'did_you_mean/levenshtein'
@@ -265,6 +266,11 @@ module NCPP
265
266
  end
266
267
  end
267
268
 
269
+ def self.get_byte_str(loc, ov, size)
270
+ addr, _ov, code_bin = resolve_code_loc(loc, ov)
271
+ code_bin.get_sect_ptr(addr,size).read_array_of_uint8(size).pack('C*')
272
+ end
273
+
268
274
  def self.find_branch_to(branch_dest, start_loc, start_ov=nil, from_func: false, find_all: false)
269
275
  start_addr, _ov, code_bin = resolve_code_loc(start_loc, start_ov)
270
276
  if branch_dest.is_a? Array
@@ -423,6 +429,40 @@ module NCPP
423
429
  gen_repl_array(addr, ov, DTYPE_IDS[:u8], [new_hex_str].pack('H*').unpack('C*'))
424
430
  end
425
431
 
432
+ def self.emulate_func(func_loc, ov, *args)
433
+ addr, ov, code_bin = resolve_code_loc(func_loc,ov)
434
+ $emu.load_overlay(ov) if !ov.nil? && ov >= 0
435
+ $emu.call_func(addr, *args)
436
+ end
437
+
438
+ def self.emu_get_mem(loc, size)
439
+ addr, ov = resolve_loc(loc)
440
+ $emu.load_overlay(ov) if !ov.nil? && ov >= 0
441
+ $emu.read_mem(addr, size)
442
+ end
443
+
444
+ def self.emu_set_mem(loc, byte_str)
445
+ addr, ov = resolve_loc(loc)
446
+ $emu.load_overlay(ov) if !ov.nil? && ov >= 0
447
+ $emu.write_mem(addr, byte_str)
448
+ end
449
+
450
+ def self.assemble_arm(asm, addr: 0)
451
+ if asm.is_a? Array
452
+ asm.map.with_index {|ins,idx| $arm_assembler.assemble(ins,addr+4*idx).unpack('L')[0] }
453
+ else
454
+ $arm_assembler.assemble(asm).unpack('L')[0]
455
+ end
456
+ end
457
+
458
+ def self.assemble_thumb(asm, addr: 0)
459
+ if asm.is_a? Array
460
+ asm.map.with_index {|ins,idx| $thumb_assembler.assemble(ins,addr+2*idx).unpack('S')[0] }
461
+ else
462
+ $thumb_assembler.assemble(asm).unpack('S')[0]
463
+ end
464
+ end
465
+
426
466
  class << self
427
467
  alias_method :get_u64, :get_dword
428
468
  alias_method :get_u32, :get_word
@@ -596,7 +636,7 @@ class Nitro::CodeBin
596
636
 
597
637
  instructions << ins
598
638
 
599
- if target = ins.target_addr
639
+ if target = ins.target_addr # if target addr not nil
600
640
  pool[target] ||= Unarm::Data.new(read_word(target), addr: target, loc: get_loc)
601
641
  end
602
642
 
@@ -698,3 +738,44 @@ class Nitro::CodeBin
698
738
  end
699
739
 
700
740
  end
741
+
742
+ #
743
+ # Various utility methods tying Unicorn to the Unarm and Nitro modules
744
+ #
745
+ class Unicorn::Emulator
746
+
747
+ def load_arm9
748
+ arm = $rom.arm9
749
+ main_added = false
750
+ arm.autoload_entries.sort_by {|e| e[:address] }.each do |e|
751
+ if e[:address] > arm.end_addr # DTCM found
752
+ add_region(Uc::Region.new(e[:address], 16*1024))
753
+ next
754
+ end
755
+ if !main_added && e[:address] > arm.start_addr # Main section found
756
+ size = e[:address] - arm.start_addr
757
+ add_section(Uc::Sect.new(arm.start_addr, arm.get_sect_ptr(arm.start_addr,size), size))
758
+ main_added = true
759
+ end
760
+ next if e[:address]+e[:size] <= e[:address]
761
+ ptr = arm.get_sect_ptr(e[:address],e[:size])
762
+ add_section(Uc::Sect.new(e[:address], ptr, e[:size]))
763
+ end
764
+ end
765
+
766
+ def load_overlay(ov_id)
767
+ ov = $rom.get_overlay(ov_id)
768
+ add_section(Uc::Sect.new(ov.start_addr, ov.get_sect_ptr(ov.start_addr, ov.size), ov.size))
769
+ end
770
+ alias_method :load_ov, :load_overlay
771
+
772
+ def call_func(addr, *args)
773
+ raise "Calling functions with more than 4 args isn't supported yet" if args.length > 4
774
+ args.each_with_index do |arg,i|
775
+ send(:"write_r#{i}", arg)
776
+ end
777
+ run(from: addr, to: read_lr, timeout_ms: 5000)
778
+ read_r0
779
+ end
780
+
781
+ end
data/lib/ncpp/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
2
  module NCPP
3
- VERSION = '0.2.0'
3
+ VERSION = '0.3.1'
4
4
  end
data/lib/ncpp.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require_relative 'nitro/nitro.rb'
2
2
  require_relative 'unarm/unarm.rb'
3
+ require_relative 'unicorn/unicorn.rb'
4
+ require_relative 'keystone/keystone.rb'
3
5
  require_relative 'ncpp/interpreter.rb'
4
6
 
5
7
  require 'json'
@@ -15,6 +17,10 @@ module NCPP
15
17
 
16
18
  alias $rom $clean_rom # In most cases the clean rom will be desired
17
19
 
20
+ $emu = nil
21
+ $arm_assembler = nil
22
+ $thumb_assembler = nil
23
+
18
24
  $config = nil
19
25
 
20
26
  NCP_CONFIG_FILE_PATH = 'ncpatcher.json'
@@ -141,6 +147,11 @@ module NCPP
141
147
 
142
148
  Unarm.load_symbols9(cfg['symbols9'].gsub(/\$\{env:([^}]+)\}/) { ENV[$1] }) unless cfg['symbols9'].empty?
143
149
  Unarm.load_symbols7(cfg['symbols7'].gsub(/\$\{env:([^}]+)\}/) { ENV[$1] }) unless cfg['symbols7'].empty?
150
+
151
+ $emu = Uc::Emu.new
152
+ $emu.load_arm9
153
+ $arm_assembler = Ks::Assembler.new
154
+ $thumb_assembler = Ks::Assembler.new(mode: Ks::KS_MODE_THUMB)
144
155
  end
145
156
 
146
157
  def self.uninstall(cfg_path = CONFIG_FILE_PATH)
@@ -426,20 +437,6 @@ module NCPP
426
437
  end
427
438
  end
428
439
 
429
- # interpreter = CFileInterpreter.new(
430
- # files, $config['gen_path'], $config['command_prefix'], extra_commands, extra_variables,
431
- # safe: safe_mode, puritan: puritan_mode
432
- # )
433
- # interpreter.run(verbose: !quiet)
434
- # lines_parsed += interpreter.lines_parsed
435
-
436
- # unless interpreter.incomplete_files.empty?
437
- # interpreter.incomplete_files.each do |file|
438
- # timestamp_cache.delete(file)
439
- # success = false
440
- # end
441
- # end
442
-
443
440
  end
444
441
 
445
442
  timestamp_cache['NCPP_VERSION'] = VERSION
@@ -447,9 +444,6 @@ module NCPP
447
444
  FileUtils.mkdir_p(File.dirname(timestamp_cache_path))
448
445
  File.write(timestamp_cache_path, JSON.generate(timestamp_cache))
449
446
 
450
- # FileUtils.mkdir_p(File.dirname(cmd_cache_path))
451
- # File.write(cmd_cache_path, JSON.generate(command_cache))
452
-
453
447
  unless quiet
454
448
  if lines_parsed > 0
455
449
  msg = "\nParsed #{lines_parsed} line#{'s' if lines_parsed != 1} across " \
Binary file
data/lib/nitro/nitro.rb CHANGED
@@ -13,6 +13,7 @@ module NitroBind
13
13
  typedef :pointer, :codebin_handle
14
14
  typedef :pointer, :ovte_handle
15
15
  typedef :pointer, :module_params_handle
16
+ typedef :pointer, :autoload_entry_handle
16
17
 
17
18
  attach_function :nitroRom_alloc, [], :rom_handle
18
19
  attach_function :nitroRom_release, [:rom_handle], :void
@@ -48,12 +49,15 @@ module NitroBind
48
49
  attach_function :codeBin_readCString, [:codebin_handle, :uint32], :string
49
50
  attach_function :codeBin_getSize, [:codebin_handle], :uint32
50
51
  attach_function :codeBin_getStartAddress, [:codebin_handle], :uint32
52
+ attach_function :codeBin_getSectPtr, [:codebin_handle, :uint32, :size_t], :pointer
51
53
 
52
54
  attach_function :armBin_alloc, [], :codebin_handle
53
55
  attach_function :armBin_release, [:codebin_handle], :void
54
56
  attach_function :armBin_load, [:codebin_handle, :string, :uint32, :uint32, :uint32, :bool], :bool
55
57
  attach_function :armBin_getEntryPointAddress, [:codebin_handle], :uint32
56
58
  attach_function :armBin_getModuleParams, [:codebin_handle], :module_params_handle
59
+ attach_function :armBin_getAutoloadEntry, [:codebin_handle, :size_t], :autoload_entry_handle
60
+ attach_function :armBin_getAutoloadEntryCount, [:codebin_handle], :size_t
57
61
  attach_function :armBin_sanityCheckAddress, [:codebin_handle, :uint32], :bool
58
62
 
59
63
  attach_function :overlayBin_alloc, [], :codebin_handle
@@ -176,7 +180,7 @@ module Nitro
176
180
  raise ArgumentError, 'step must be 1, 2, 4, or 8 (bytes)' unless [1,2,4,8].include? step
177
181
  raise ArgumentError, 'range must be a Range' unless range.is_a? Range
178
182
 
179
- clamped = Range.new([range.begin || start_addr, start_addr].max, [range.end || end_addr, end_addr].min)
183
+ clamped = Range.new(range.begin || start_addr, [range.end || end_addr, end_addr].min)
180
184
 
181
185
  clamped.step(step).map { |addr| [send(:"read#{step * 8}", addr), addr] }
182
186
  end
@@ -211,17 +215,25 @@ module Nitro
211
215
  end
212
216
  end
213
217
 
214
- def read_cstring(start_addr)
215
- codeBin_readCString(@ptr, start_addr)
218
+ def read_cstring(addr)
219
+ codeBin_readCString(@ptr, addr)
216
220
  end
217
221
  alias_method :read_cstr, :read_cstring
218
222
 
223
+ def get_section_ptr(addr, sect_size)
224
+ ptr = FFI::MemoryPointer.new(:pointer, 1)
225
+ ptr.write_pointer(codeBin_getSectPtr(@ptr, addr, sect_size))
226
+ raise "Could not read #{sect_size} bytes from address #{addr.to_hex}" if ptr.read_pointer == FFI::Pointer::NULL
227
+ ptr.read_pointer
228
+ end
229
+ alias_method :get_sect_ptr, :get_section_ptr
230
+
219
231
  end
220
232
 
221
233
  class ArmBin < CodeBin
222
234
  include NitroBind
223
235
 
224
- attr_reader :module_params
236
+ attr_reader :module_params, :autoload_entries
225
237
 
226
238
  class ModuleParams < FFI::Struct
227
239
  layout :autoload_list_start, :uint32,
@@ -235,10 +247,17 @@ module Nitro
235
247
  :nitro_code_le, :uint32
236
248
  end
237
249
 
250
+ class AutoLoadEntry < FFI::Struct
251
+ layout :address, :uint32,
252
+ :size, :uint32,
253
+ :bss_size, :uint32,
254
+ :data_offset, :uint32
255
+ end
256
+
238
257
  def initialize(args = {})
239
258
  if args.has_key? :file_path
240
259
  @ptr = FFI::AutoPointer.new(armBin_alloc, method(:armBin_release))
241
- if not File.exist? args[:file_path]
260
+ if !File.exist?(args[:file_path])
242
261
  puts "Error: #{args[:file_path]} does not exist"
243
262
  raise 'ArmBin initialization failed'
244
263
  end
@@ -253,6 +272,9 @@ module Nitro
253
272
  end
254
273
 
255
274
  @module_params = ModuleParams.new(armBin_getModuleParams(@ptr))
275
+ @autoload_entries = []
276
+ autoload_entry_count = armBin_getAutoloadEntryCount(@ptr)
277
+ autoload_entry_count.times {|id| autoload_entries << AutoLoadEntry.new(armBin_getAutoloadEntry(@ptr,id)) }
256
278
  end
257
279
 
258
280
  def entry_point_address
@@ -0,0 +1,196 @@
1
+ # For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.rb]
2
+
3
+ module UnicornEngine
4
+
5
+ # ARM CPU
6
+
7
+ UC_CPU_ARM_926 = 0
8
+ UC_CPU_ARM_946 = 1
9
+ UC_CPU_ARM_1026 = 2
10
+ UC_CPU_ARM_1136_R2 = 3
11
+ UC_CPU_ARM_1136 = 4
12
+ UC_CPU_ARM_1176 = 5
13
+ UC_CPU_ARM_11MPCORE = 6
14
+ UC_CPU_ARM_CORTEX_M0 = 7
15
+ UC_CPU_ARM_CORTEX_M3 = 8
16
+ UC_CPU_ARM_CORTEX_M4 = 9
17
+ UC_CPU_ARM_CORTEX_M7 = 10
18
+ UC_CPU_ARM_CORTEX_M33 = 11
19
+ UC_CPU_ARM_CORTEX_R5 = 12
20
+ UC_CPU_ARM_CORTEX_R5F = 13
21
+ UC_CPU_ARM_CORTEX_A7 = 14
22
+ UC_CPU_ARM_CORTEX_A8 = 15
23
+ UC_CPU_ARM_CORTEX_A9 = 16
24
+ UC_CPU_ARM_CORTEX_A15 = 17
25
+ UC_CPU_ARM_TI925T = 18
26
+ UC_CPU_ARM_SA1100 = 19
27
+ UC_CPU_ARM_SA1110 = 20
28
+ UC_CPU_ARM_PXA250 = 21
29
+ UC_CPU_ARM_PXA255 = 22
30
+ UC_CPU_ARM_PXA260 = 23
31
+ UC_CPU_ARM_PXA261 = 24
32
+ UC_CPU_ARM_PXA262 = 25
33
+ UC_CPU_ARM_PXA270 = 26
34
+ UC_CPU_ARM_PXA270A0 = 27
35
+ UC_CPU_ARM_PXA270A1 = 28
36
+ UC_CPU_ARM_PXA270B0 = 29
37
+ UC_CPU_ARM_PXA270B1 = 30
38
+ UC_CPU_ARM_PXA270C0 = 31
39
+ UC_CPU_ARM_PXA270C5 = 32
40
+ UC_CPU_ARM_MAX = 33
41
+ UC_CPU_ARM_ENDING = 34
42
+
43
+ # ARM registers
44
+
45
+ UC_ARM_REG_INVALID = 0
46
+ UC_ARM_REG_APSR = 1
47
+ UC_ARM_REG_APSR_NZCV = 2
48
+ UC_ARM_REG_CPSR = 3
49
+ UC_ARM_REG_FPEXC = 4
50
+ UC_ARM_REG_FPINST = 5
51
+ UC_ARM_REG_FPSCR = 6
52
+ UC_ARM_REG_FPSCR_NZCV = 7
53
+ UC_ARM_REG_FPSID = 8
54
+ UC_ARM_REG_ITSTATE = 9
55
+ UC_ARM_REG_LR = 10
56
+ UC_ARM_REG_PC = 11
57
+ UC_ARM_REG_SP = 12
58
+ UC_ARM_REG_SPSR = 13
59
+ UC_ARM_REG_D0 = 14
60
+ UC_ARM_REG_D1 = 15
61
+ UC_ARM_REG_D2 = 16
62
+ UC_ARM_REG_D3 = 17
63
+ UC_ARM_REG_D4 = 18
64
+ UC_ARM_REG_D5 = 19
65
+ UC_ARM_REG_D6 = 20
66
+ UC_ARM_REG_D7 = 21
67
+ UC_ARM_REG_D8 = 22
68
+ UC_ARM_REG_D9 = 23
69
+ UC_ARM_REG_D10 = 24
70
+ UC_ARM_REG_D11 = 25
71
+ UC_ARM_REG_D12 = 26
72
+ UC_ARM_REG_D13 = 27
73
+ UC_ARM_REG_D14 = 28
74
+ UC_ARM_REG_D15 = 29
75
+ UC_ARM_REG_D16 = 30
76
+ UC_ARM_REG_D17 = 31
77
+ UC_ARM_REG_D18 = 32
78
+ UC_ARM_REG_D19 = 33
79
+ UC_ARM_REG_D20 = 34
80
+ UC_ARM_REG_D21 = 35
81
+ UC_ARM_REG_D22 = 36
82
+ UC_ARM_REG_D23 = 37
83
+ UC_ARM_REG_D24 = 38
84
+ UC_ARM_REG_D25 = 39
85
+ UC_ARM_REG_D26 = 40
86
+ UC_ARM_REG_D27 = 41
87
+ UC_ARM_REG_D28 = 42
88
+ UC_ARM_REG_D29 = 43
89
+ UC_ARM_REG_D30 = 44
90
+ UC_ARM_REG_D31 = 45
91
+ UC_ARM_REG_FPINST2 = 46
92
+ UC_ARM_REG_MVFR0 = 47
93
+ UC_ARM_REG_MVFR1 = 48
94
+ UC_ARM_REG_MVFR2 = 49
95
+ UC_ARM_REG_Q0 = 50
96
+ UC_ARM_REG_Q1 = 51
97
+ UC_ARM_REG_Q2 = 52
98
+ UC_ARM_REG_Q3 = 53
99
+ UC_ARM_REG_Q4 = 54
100
+ UC_ARM_REG_Q5 = 55
101
+ UC_ARM_REG_Q6 = 56
102
+ UC_ARM_REG_Q7 = 57
103
+ UC_ARM_REG_Q8 = 58
104
+ UC_ARM_REG_Q9 = 59
105
+ UC_ARM_REG_Q10 = 60
106
+ UC_ARM_REG_Q11 = 61
107
+ UC_ARM_REG_Q12 = 62
108
+ UC_ARM_REG_Q13 = 63
109
+ UC_ARM_REG_Q14 = 64
110
+ UC_ARM_REG_Q15 = 65
111
+ UC_ARM_REG_R0 = 66
112
+ UC_ARM_REG_R1 = 67
113
+ UC_ARM_REG_R2 = 68
114
+ UC_ARM_REG_R3 = 69
115
+ UC_ARM_REG_R4 = 70
116
+ UC_ARM_REG_R5 = 71
117
+ UC_ARM_REG_R6 = 72
118
+ UC_ARM_REG_R7 = 73
119
+ UC_ARM_REG_R8 = 74
120
+ UC_ARM_REG_R9 = 75
121
+ UC_ARM_REG_R10 = 76
122
+ UC_ARM_REG_R11 = 77
123
+ UC_ARM_REG_R12 = 78
124
+ UC_ARM_REG_S0 = 79
125
+ UC_ARM_REG_S1 = 80
126
+ UC_ARM_REG_S2 = 81
127
+ UC_ARM_REG_S3 = 82
128
+ UC_ARM_REG_S4 = 83
129
+ UC_ARM_REG_S5 = 84
130
+ UC_ARM_REG_S6 = 85
131
+ UC_ARM_REG_S7 = 86
132
+ UC_ARM_REG_S8 = 87
133
+ UC_ARM_REG_S9 = 88
134
+ UC_ARM_REG_S10 = 89
135
+ UC_ARM_REG_S11 = 90
136
+ UC_ARM_REG_S12 = 91
137
+ UC_ARM_REG_S13 = 92
138
+ UC_ARM_REG_S14 = 93
139
+ UC_ARM_REG_S15 = 94
140
+ UC_ARM_REG_S16 = 95
141
+ UC_ARM_REG_S17 = 96
142
+ UC_ARM_REG_S18 = 97
143
+ UC_ARM_REG_S19 = 98
144
+ UC_ARM_REG_S20 = 99
145
+ UC_ARM_REG_S21 = 100
146
+ UC_ARM_REG_S22 = 101
147
+ UC_ARM_REG_S23 = 102
148
+ UC_ARM_REG_S24 = 103
149
+ UC_ARM_REG_S25 = 104
150
+ UC_ARM_REG_S26 = 105
151
+ UC_ARM_REG_S27 = 106
152
+ UC_ARM_REG_S28 = 107
153
+ UC_ARM_REG_S29 = 108
154
+ UC_ARM_REG_S30 = 109
155
+ UC_ARM_REG_S31 = 110
156
+ UC_ARM_REG_C1_C0_2 = 111
157
+ UC_ARM_REG_C13_C0_2 = 112
158
+ UC_ARM_REG_C13_C0_3 = 113
159
+ UC_ARM_REG_IPSR = 114
160
+ UC_ARM_REG_MSP = 115
161
+ UC_ARM_REG_PSP = 116
162
+ UC_ARM_REG_CONTROL = 117
163
+ UC_ARM_REG_IAPSR = 118
164
+ UC_ARM_REG_EAPSR = 119
165
+ UC_ARM_REG_XPSR = 120
166
+ UC_ARM_REG_EPSR = 121
167
+ UC_ARM_REG_IEPSR = 122
168
+ UC_ARM_REG_PRIMASK = 123
169
+ UC_ARM_REG_BASEPRI = 124
170
+ UC_ARM_REG_BASEPRI_MAX = 125
171
+ UC_ARM_REG_FAULTMASK = 126
172
+ UC_ARM_REG_APSR_NZCVQ = 127
173
+ UC_ARM_REG_APSR_G = 128
174
+ UC_ARM_REG_APSR_NZCVQG = 129
175
+ UC_ARM_REG_IAPSR_NZCVQ = 130
176
+ UC_ARM_REG_IAPSR_G = 131
177
+ UC_ARM_REG_IAPSR_NZCVQG = 132
178
+ UC_ARM_REG_EAPSR_NZCVQ = 133
179
+ UC_ARM_REG_EAPSR_G = 134
180
+ UC_ARM_REG_EAPSR_NZCVQG = 135
181
+ UC_ARM_REG_XPSR_NZCVQ = 136
182
+ UC_ARM_REG_XPSR_G = 137
183
+ UC_ARM_REG_XPSR_NZCVQG = 138
184
+ UC_ARM_REG_CP_REG = 139
185
+ UC_ARM_REG_ESR = 140
186
+ UC_ARM_REG_ENDING = 141
187
+
188
+ # alias registers
189
+ UC_ARM_REG_R13 = 12
190
+ UC_ARM_REG_R14 = 10
191
+ UC_ARM_REG_R15 = 11
192
+ UC_ARM_REG_SB = 75
193
+ UC_ARM_REG_SL = 76
194
+ UC_ARM_REG_FP = 77
195
+ UC_ARM_REG_IP = 78
196
+ end
Binary file
Binary file
@@ -0,0 +1,204 @@
1
+ require 'ffi'
2
+
3
+ require_relative 'arm_const.rb'
4
+ require_relative 'unicorn_const.rb'
5
+
6
+ include UnicornEngine
7
+
8
+ module UnicornBind
9
+ extend FFI::Library
10
+ ffi_lib [
11
+ File.expand_path("unicorn", __dir__),
12
+ File.expand_path("unicorn.dylib", __dir__),
13
+ File.expand_path("unicorn.so", __dir__),
14
+ ]
15
+
16
+ typedef :pointer, :uc_engine # ptr to uc_engine instance
17
+ typedef :pointer, :uc_engine_handle # ptr to a uc_engine ptr
18
+ typedef :pointer, :reg_val_ptr
19
+ typedef :pointer, :reg_val_ptr_arr
20
+ typedef :pointer, :reg_id_arr
21
+ typedef :uint64, :addr
22
+ typedef :uint, :uc_arch
23
+ typedef :uint, :uc_mode
24
+ typedef :uint, :uc_err
25
+ typedef :uint, :uc_query_type
26
+ typedef :uint, :uc_control_type
27
+ typedef :int, :reg_id
28
+
29
+ attach_function :uc_version, [:pointer,:pointer], :uint
30
+ attach_function :uc_arch_supported, [:uc_arch], :bool
31
+ attach_function :uc_open, [:uc_arch, :uc_mode, :uc_engine_handle], :uc_err
32
+ attach_function :uc_close, [:uc_engine], :uc_err
33
+ attach_function :uc_query, [:uc_engine, :uc_query_type, :pointer], :uc_err
34
+ attach_function :uc_ctl, [:uc_engine, :uc_control_type, :varargs], :uc_err
35
+ attach_function :uc_errno, [:uc_engine], :uc_err
36
+ attach_function :uc_strerror, [:uc_err], :string
37
+ attach_function :uc_reg_write, [:uc_engine, :reg_id, :reg_val_ptr], :uc_err
38
+ attach_function :uc_reg_read, [:uc_engine, :reg_id, :reg_val_ptr], :uc_err
39
+ attach_function :uc_reg_write_batch, [:uc_engine, :reg_id_arr, :reg_val_ptr_arr, :int], :uc_err
40
+ attach_function :uc_reg_read_batch, [:uc_engine, :reg_id_arr, :reg_val_ptr_arr, :int], :uc_err
41
+ attach_function :uc_mem_write, [:uc_engine, :addr, :pointer, :uint64], :uc_err
42
+ attach_function :uc_mem_read, [:uc_engine, :addr, :pointer, :uint64], :uc_err
43
+ attach_function :uc_emu_start, [:uc_engine, :addr, :addr, :uint64, :size_t], :uc_err
44
+ attach_function :uc_emu_stop, [:uc_engine], :uc_err
45
+ attach_function :uc_mem_map, [:uc_engine, :addr, :uint64, :uint32], :uc_err
46
+ attach_function :uc_mem_map_ptr, [:uc_engine, :addr, :uint64, :uint32, :pointer], :uc_err
47
+ attach_function :uc_mem_unmap, [:uc_engine, :addr, :uint64], :uc_err
48
+ attach_function :uc_mem_protect, [:uc_engine, :addr, :uint64, :uint32], :uc_err
49
+
50
+ REG_ID = {
51
+ r0: UC_ARM_REG_R0,
52
+ r1: UC_ARM_REG_R1,
53
+ r2: UC_ARM_REG_R2,
54
+ r3: UC_ARM_REG_R3,
55
+ r4: UC_ARM_REG_R4,
56
+ r5: UC_ARM_REG_R5,
57
+ r6: UC_ARM_REG_R6,
58
+ r7: UC_ARM_REG_R7,
59
+ r8: UC_ARM_REG_R8,
60
+ r9: UC_ARM_REG_R9,
61
+ r10: UC_ARM_REG_R10,
62
+ r11: UC_ARM_REG_R11,
63
+ r12: UC_ARM_REG_R12,
64
+ sp: UC_ARM_REG_SP,
65
+ lr: UC_ARM_REG_LR,
66
+ pc: UC_ARM_REG_PC,
67
+ cpsr: UC_ARM_REG_CPSR,
68
+ spsr: UC_ARM_REG_SPSR
69
+ }.freeze
70
+ end
71
+
72
+ module Unicorn
73
+ extend UnicornBind
74
+
75
+ class Region
76
+ attr_reader :addr, :size, :prot, :end_addr
77
+ def initialize(addr, size, prot = UC_PROT_ALL)
78
+ @addr = addr
79
+ @size = size
80
+ @prot = prot
81
+ @end_addr = addr + size
82
+ end
83
+ end
84
+
85
+ NDS_REGIONS = [
86
+ Region.new(0x1ff8000, 32*1024), # ITCM -> 32KB
87
+ Region.new(0x2000000, 4*1024*1024), # Main memory -> 4MB
88
+ Region.new(0x4000000, 64*1024*1024), # I/O and VRAM -> 64MB
89
+ Region.new(0xffff000, 32*1024) # BIOS -> 32KB
90
+ ].freeze
91
+
92
+ class Section
93
+ attr_reader :addr, :ptr, :size, :end_addr
94
+ def initialize(addr, ffi_ptr, size)
95
+ @addr = addr
96
+ @ptr = ffi_ptr
97
+ @size = size
98
+ @end_addr = addr + size
99
+ end
100
+ end
101
+ Sect = Section
102
+
103
+ class Emulator
104
+ include UnicornBind
105
+
106
+ def initialize(arch: UC_ARCH_ARM, mode: UC_MODE_ARM946, regions: NDS_REGIONS, sections: [], registers: {})
107
+
108
+ FFI::MemoryPointer.new(:pointer, 1) do |ptr|
109
+ safe_call(:uc_open, arch, mode, ptr)
110
+ @engine = FFI::AutoPointer.new(ptr.read_pointer, method(:uc_close))
111
+ end
112
+
113
+ regions.each { add_region(it) } unless regions.empty?
114
+ sections.each { add_sect(it) } unless sections.empty?
115
+ registers.each {|r,v| write_register(r,v) } unless registers.empty?
116
+ end
117
+
118
+ def run(from: nil, to: -1, timeout_ms: 0, max_ins: 0)
119
+ raise "The 'from' parameter must be specified" if from.nil?
120
+ if to == -1 && timeout_ms == 0 && max_ins == 0
121
+ raise "The 'to' parameter must be specified if 'timeout_ms' or 'max_ins' are not"
122
+ end
123
+ safe_call(:uc_emu_start, @engine, from, to, timeout_ms, max_ins)
124
+ end
125
+
126
+ def add_region(region)
127
+ safe_call(:uc_mem_map, @engine, region.addr, region.size, region.prot)
128
+ end
129
+
130
+ def add_section(sect)
131
+ safe_call(:uc_mem_write, @engine, sect.addr, sect.ptr, sect.size)
132
+ end
133
+ alias_method :add_sect, :add_section
134
+
135
+ def write_mem(addr, byte_str)
136
+ FFI::MemoryPointer.new(:uint8, byte_str.bytesize) do |ptr|
137
+ ptr.write_array_of_uint8(byte_str.bytes)
138
+ safe_call(:uc_mem_write, @engine, addr, ptr, byte_str.bytesize)
139
+ end
140
+ end
141
+
142
+ def read_mem(addr, size)
143
+ byte_str = nil
144
+ FFI::MemoryPointer.new(:uint8, size) do |ptr|
145
+ safe_call(:uc_mem_read, @engine, addr, ptr, size)
146
+ byte_str = ptr.read_array_of_uint8(size).pack('C*')
147
+ end
148
+ byte_str
149
+ end
150
+
151
+ def write_register(reg, val)
152
+ FFI::MemoryPointer.new(:int32, 1) do |pv|
153
+ pv.write_int(val)
154
+ safe_call(:uc_reg_write, @engine, REG_ID[reg], pv)
155
+ end
156
+ end
157
+ alias_method :write_reg, :write_register
158
+
159
+ def write_registers(regs_h)
160
+ regs_h.each {|r,v| write_register(r,v) }
161
+ end
162
+ alias_method :write_regs, :write_registers
163
+
164
+ REG_ID.each do |name, id|
165
+ define_method("write_#{name.to_s}".to_sym) do |val|
166
+ write_register(name, val)
167
+ end
168
+ end
169
+
170
+ def read_register(reg)
171
+ val = nil
172
+ FFI::MemoryPointer.new(:int32, 1) do |pv|
173
+ safe_call(:uc_reg_read, @engine, REG_ID[reg], pv)
174
+ val = pv.read_int32
175
+ end
176
+ val
177
+ end
178
+ alias_method :read_reg, :read_register
179
+
180
+ def read_registers(reg_names = REG_ID.keys)
181
+ regs_h = {}
182
+ reg_names.each {|r| regs_h[r] = read_register(r) }
183
+ regs_h
184
+ end
185
+ alias_method :read_regs, :read_registers
186
+
187
+ REG_ID.each do |name, id|
188
+ define_method("read_#{name.to_s}".to_sym) do
189
+ read_register(name)
190
+ end
191
+ end
192
+
193
+ private
194
+ def safe_call(meth_sym, *args)
195
+ err = send(meth_sym, *args)
196
+ raise "Error from #{meth_sym.to_s}: #{uc_strerror(err)}" if err != UC_ERR_OK
197
+ end
198
+ end
199
+
200
+ Emu = Emulator
201
+
202
+ end
203
+
204
+ Uc = Unicorn
@@ -0,0 +1,152 @@
1
+ # For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.rb]
2
+
3
+ module UnicornEngine
4
+ UC_API_MAJOR = 2
5
+ UC_API_MINOR = 1
6
+ UC_API_PATCH = 4
7
+ UC_API_EXTRA = 255
8
+ UC_VERSION_MAJOR = 2
9
+ UC_VERSION_MINOR = 1
10
+ UC_VERSION_PATCH = 4
11
+ UC_VERSION_EXTRA = 255
12
+ UC_SECOND_SCALE = 1000000
13
+ UC_MILISECOND_SCALE = 1000
14
+ UC_ARCH_ARM = 1
15
+ UC_ARCH_ARM64 = 2
16
+ UC_ARCH_MIPS = 3
17
+ UC_ARCH_X86 = 4
18
+ UC_ARCH_PPC = 5
19
+ UC_ARCH_SPARC = 6
20
+ UC_ARCH_M68K = 7
21
+ UC_ARCH_RISCV = 8
22
+ UC_ARCH_S390X = 9
23
+ UC_ARCH_TRICORE = 10
24
+ UC_ARCH_MAX = 11
25
+
26
+ UC_MODE_LITTLE_ENDIAN = 0
27
+ UC_MODE_BIG_ENDIAN = 1073741824
28
+
29
+ UC_MODE_ARM = 0
30
+ UC_MODE_THUMB = 16
31
+ UC_MODE_MCLASS = 32
32
+ UC_MODE_V8 = 64
33
+ UC_MODE_ARMBE8 = 1024
34
+ UC_MODE_ARM926 = 128
35
+ UC_MODE_ARM946 = 256
36
+ UC_MODE_ARM1176 = 512
37
+ UC_MODE_MICRO = 16
38
+ UC_MODE_MIPS3 = 32
39
+ UC_MODE_MIPS32R6 = 64
40
+ UC_MODE_MIPS32 = 4
41
+ UC_MODE_MIPS64 = 8
42
+ UC_MODE_16 = 2
43
+ UC_MODE_32 = 4
44
+ UC_MODE_64 = 8
45
+ UC_MODE_PPC32 = 4
46
+ UC_MODE_PPC64 = 8
47
+ UC_MODE_QPX = 16
48
+ UC_MODE_SPARC32 = 4
49
+ UC_MODE_SPARC64 = 8
50
+ UC_MODE_V9 = 16
51
+ UC_MODE_RISCV32 = 4
52
+ UC_MODE_RISCV64 = 8
53
+
54
+ UC_ERR_OK = 0
55
+ UC_ERR_NOMEM = 1
56
+ UC_ERR_ARCH = 2
57
+ UC_ERR_HANDLE = 3
58
+ UC_ERR_MODE = 4
59
+ UC_ERR_VERSION = 5
60
+ UC_ERR_READ_UNMAPPED = 6
61
+ UC_ERR_WRITE_UNMAPPED = 7
62
+ UC_ERR_FETCH_UNMAPPED = 8
63
+ UC_ERR_HOOK = 9
64
+ UC_ERR_INSN_INVALID = 10
65
+ UC_ERR_MAP = 11
66
+ UC_ERR_WRITE_PROT = 12
67
+ UC_ERR_READ_PROT = 13
68
+ UC_ERR_FETCH_PROT = 14
69
+ UC_ERR_ARG = 15
70
+ UC_ERR_READ_UNALIGNED = 16
71
+ UC_ERR_WRITE_UNALIGNED = 17
72
+ UC_ERR_FETCH_UNALIGNED = 18
73
+ UC_ERR_HOOK_EXIST = 19
74
+ UC_ERR_RESOURCE = 20
75
+ UC_ERR_EXCEPTION = 21
76
+ UC_ERR_OVERFLOW = 22
77
+
78
+ UC_PROT_NONE = 0
79
+ UC_PROT_READ = 1
80
+ UC_PROT_WRITE = 2
81
+ UC_PROT_EXEC = 4
82
+ UC_PROT_ALL = 7
83
+ UC_MEM_READ = 16
84
+ UC_MEM_WRITE = 17
85
+ UC_MEM_FETCH = 18
86
+ UC_MEM_READ_UNMAPPED = 19
87
+ UC_MEM_WRITE_UNMAPPED = 20
88
+ UC_MEM_FETCH_UNMAPPED = 21
89
+ UC_MEM_WRITE_PROT = 22
90
+ UC_MEM_READ_PROT = 23
91
+ UC_MEM_FETCH_PROT = 24
92
+ UC_MEM_READ_AFTER = 25
93
+
94
+ UC_TCG_OP_SUB = 0
95
+ UC_TCG_OP_FLAG_CMP = 1
96
+ UC_TCG_OP_FLAG_DIRECT = 2
97
+ UC_HOOK_INTR = 1
98
+ UC_HOOK_INSN = 2
99
+ UC_HOOK_CODE = 4
100
+ UC_HOOK_BLOCK = 8
101
+ UC_HOOK_MEM_READ_UNMAPPED = 16
102
+ UC_HOOK_MEM_WRITE_UNMAPPED = 32
103
+ UC_HOOK_MEM_FETCH_UNMAPPED = 64
104
+ UC_HOOK_MEM_READ_PROT = 128
105
+ UC_HOOK_MEM_WRITE_PROT = 256
106
+ UC_HOOK_MEM_FETCH_PROT = 512
107
+ UC_HOOK_MEM_READ = 1024
108
+ UC_HOOK_MEM_WRITE = 2048
109
+ UC_HOOK_MEM_FETCH = 4096
110
+ UC_HOOK_MEM_READ_AFTER = 8192
111
+ UC_HOOK_INSN_INVALID = 16384
112
+ UC_HOOK_EDGE_GENERATED = 32768
113
+ UC_HOOK_TCG_OPCODE = 65536
114
+ UC_HOOK_TLB_FILL = 131072
115
+ UC_HOOK_MEM_UNMAPPED = 112
116
+ UC_HOOK_MEM_PROT = 896
117
+ UC_HOOK_MEM_READ_INVALID = 144
118
+ UC_HOOK_MEM_WRITE_INVALID = 288
119
+ UC_HOOK_MEM_FETCH_INVALID = 576
120
+ UC_HOOK_MEM_INVALID = 1008
121
+ UC_HOOK_MEM_VALID = 7168
122
+ UC_QUERY_MODE = 1
123
+ UC_QUERY_PAGE_SIZE = 2
124
+ UC_QUERY_ARCH = 3
125
+ UC_QUERY_TIMEOUT = 4
126
+
127
+ UC_CTL_IO_NONE = 0
128
+ UC_CTL_IO_WRITE = 1
129
+ UC_CTL_IO_READ = 2
130
+ UC_CTL_IO_READ_WRITE = 3
131
+
132
+ UC_TLB_CPU = 0
133
+ UC_TLB_VIRTUAL = 1
134
+
135
+ UC_CTL_UC_MODE = 0
136
+ UC_CTL_UC_PAGE_SIZE = 1
137
+ UC_CTL_UC_ARCH = 2
138
+ UC_CTL_UC_TIMEOUT = 3
139
+ UC_CTL_UC_USE_EXITS = 4
140
+ UC_CTL_UC_EXITS_CNT = 5
141
+ UC_CTL_UC_EXITS = 6
142
+ UC_CTL_CPU_MODEL = 7
143
+ UC_CTL_TB_REQUEST_CACHE = 8
144
+ UC_CTL_TB_REMOVE_CACHE = 9
145
+ UC_CTL_TB_FLUSH = 10
146
+ UC_CTL_TLB_FLUSH = 11
147
+ UC_CTL_TLB_TYPE = 12
148
+ UC_CTL_TCG_BUFFER_SIZE = 13
149
+ UC_CTL_CONTEXT_MODE = 14
150
+ UC_CTL_CONTEXT_CPU = 1
151
+ UC_CTL_CONTEXT_MEMORY = 2
152
+ end
@@ -0,0 +1,3 @@
1
+ module Unicorn
2
+ VERSION = "2.1.4"
3
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: NCPrePatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: x86_64-darwin-24
6
6
  authors:
7
7
  - Will Smith
@@ -55,6 +55,11 @@ files:
55
55
  - example/README.md
56
56
  - example/disasm.rb
57
57
  - exe/ncpp
58
+ - lib/keystone/arm_const.rb
59
+ - lib/keystone/keystone.dylib
60
+ - lib/keystone/keystone.rb
61
+ - lib/keystone/keystone_const.rb
62
+ - lib/keystone/version.rb
58
63
  - lib/ncpp.rb
59
64
  - lib/ncpp/commands.rb
60
65
  - lib/ncpp/interpreter.rb
@@ -66,6 +71,12 @@ files:
66
71
  - lib/nitro/nitro.rb
67
72
  - lib/unarm/unarm.dylib
68
73
  - lib/unarm/unarm.rb
74
+ - lib/unicorn/arm_const.rb
75
+ - lib/unicorn/unicorn.a
76
+ - lib/unicorn/unicorn.dylib
77
+ - lib/unicorn/unicorn.rb
78
+ - lib/unicorn/unicorn_const.rb
79
+ - lib/unicorn/version.rb
69
80
  homepage: https://github.com/pete420griff/NCPrePatcher
70
81
  licenses:
71
82
  - GPL-3.0-only
@@ -85,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
96
  - !ruby/object:Gem::Version
86
97
  version: '0'
87
98
  requirements: []
88
- rubygems_version: 3.7.2
99
+ rubygems_version: 4.0.0
89
100
  specification_version: 4
90
101
  summary: A preprocessor for NCPatcher
91
102
  test_files: []