NCPrePatcher 0.2.0 → 0.3.2
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 +4 -4
- data/LICENSE.txt +674 -674
- data/README.md +68 -65
- data/example/README.md +3 -3
- data/example/disasm.rb +30 -34
- data/lib/keystone/arm_const.rb +7 -0
- data/lib/keystone/keystone.rb +76 -0
- data/lib/keystone/keystone_const.rb +97 -0
- data/lib/keystone/version.rb +3 -0
- data/lib/ncpp/commands.rb +78 -5
- data/lib/ncpp/interpreter.rb +4 -3
- data/lib/ncpp/types.rb +1 -1
- data/lib/ncpp/utils.rb +84 -3
- data/lib/ncpp/version.rb +1 -1
- data/lib/ncpp.rb +14 -20
- data/lib/nitro/nitro.rb +27 -5
- data/lib/unicorn/arm_const.rb +196 -0
- data/lib/unicorn/unicorn.rb +204 -0
- data/lib/unicorn/unicorn_const.rb +152 -0
- data/lib/unicorn/version.rb +3 -0
- metadata +11 -5
- data/lib/nitro/nitro.dll +0 -0
- data/lib/unarm/unarm.dll +0 -0
data/lib/ncpp/version.rb
CHANGED
data/lib/ncpp.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
require_relative 'nitro/nitro
|
|
2
|
-
require_relative 'unarm/unarm
|
|
3
|
-
require_relative '
|
|
1
|
+
require_relative 'nitro/nitro'
|
|
2
|
+
require_relative 'unarm/unarm'
|
|
3
|
+
require_relative 'unicorn/unicorn'
|
|
4
|
+
require_relative 'keystone/keystone'
|
|
5
|
+
require_relative 'ncpp/interpreter'
|
|
4
6
|
|
|
5
7
|
require 'json'
|
|
6
8
|
require 'optparse'
|
|
@@ -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 " \
|
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(
|
|
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(
|
|
215
|
-
codeBin_readCString(@ptr,
|
|
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
|
|
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
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
|
|
3
|
+
require_relative 'arm_const'
|
|
4
|
+
require_relative 'unicorn_const'
|
|
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
|