-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathindex.js
284 lines (262 loc) · 8.88 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
const arch = Process.arch;
const thumb_erase_maskcode = 0xfffffffffffe
var breakpoint_desc = {
"breakpoint_ins" :'',
"writer" : null,
"thumb_writer":null,
"thumb_breakpoint_ins":'00be'
//长度 thumb恒为2 arm,arm64恒为4
};
(_=>{
switch (arch) {
case "arm64":
breakpoint_desc["breakpoint_ins"] = '000020d4'
breakpoint_desc["writer"] = Arm64Writer
// break_mem.writeByteArray(hex2buf(breakpoint_ins))
break
case "arm":
breakpoint_desc["breakpoint_ins"] = '700020e1'
breakpoint_desc["writer"] = ArmWriter
breakpoint_desc["thumb_writer"]=ThumbWriter
break
default:
console.error(arch,' not support')
}
})()
function buf2hex(buffer) { // buffer is an ArrayBuffer
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
function hex2buf(hex){
return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)})).buffer
}
/**
* @param {NativePointer} pc_addr
* @returns 是否为thumb,true为thunb,false不是thumb
* fixme 因为pc拿到的地址恒为偶数,所以不得不用lr来判断
*/
function check_pc_thumb(pc_addr){
return (pc_addr % 2 == 1)
}
/**
* @param pc_addr 目标断点
* @returns {boolean} 返回真是断点,返回假不是断点
*/
function checkbreakpoint(pc_addr){
switch(arch){
case "arm64":
return buf2hex(rpc.exports.readdata(pc_addr,4)) === breakpoint_desc["breakpoint_ins"]
case "arm":
if(check_pc_thumb(pc_addr)){
return buf2hex(rpc.exports.readdata(pc_addr.and(thumb_erase_maskcode),2)) === breakpoint_desc["breakpoint_ins"]
}else{
return buf2hex(rpc.exports.readdata(pc_addr,4)) === breakpoint_desc["thumb_breakpoint_ins"]
}
default:
console.error(arch,' not support')
}
}
/**
* 通过不同的writer来写不同的断点
* 原理是先恢复内存保护然后设置软断点
* 自己的断点被访问后,恢复断点,设置内存保护
* cmd 1
*
* @param break_info 断点信息
* @param writer 不同的writer
* @returns {boolean} 返回真假 真表示处理 假表示异常未处理
*/
function resume_pagebreak_write_softbreakpoint(break_info,writer){
let pc_addr = ptr(break_info['current_pc']);
let lr_addr = ptr(break_info['current_lr']);
//如果是thumb指令集地址加1,arm和arm64指令集不需要加1
if(check_pc_thumb(lr_addr)){
pc_addr = pc_addr.add(1)
}
const break_page_info = break_info['break_page_info'];
//获取当前指令长度
const size = Instruction.parse(pc_addr).size;
//恢复原始的内存保护
rpc.exports.setpageprotect(break_page_info[0],break_page_info[1])
//把要写的断点移到下个条指令
pc_addr = pc_addr.add(size)
let ins_writer = new writer(pc_addr);
if(check_pc_thumb(lr_addr)){
ins_writer = new breakpoint_desc["thumb_writer"](pc_addr.and(thumb_erase_maskcode))
}
const store_size = Instruction.parse(pc_addr).size;
//保存断点消息
let send_dict = {};
send_dict['break_addr'] = pc_addr
send_dict['break_len'] = store_size
send_dict['ins_content'] = buf2hex(rpc.exports.readdata(pc_addr.and(thumb_erase_maskcode),store_size))
send_dict['__tag'] = 'set_soft_breakpoint'
send(send_dict)
//等待返回结果
let payload = null;
const op = recv('set_soft_breakpoint_ret', function (value) {
payload = value.payload
});
op.wait()
//写断点
if(!checkbreakpoint(pc_addr)){
Memory.patchCode(pc_addr, store_size, function (code) {
//不同arch的断点写法不一样
//todo 修复在libc中写代码段崩溃的问题
switch(arch){
case "arm64":
ins_writer.putBytes(hex2buf(breakpoint_desc["breakpoint_ins"]))
ins_writer.flush()
break
case "arm":
if(check_pc_thumb(pc_addr)){
//thumb
ins_writer.putBytes(hex2buf(breakpoint_desc["thumb_breakpoint_ins"]))
ins_writer.flush()
}else{
ins_writer.putBytes(hex2buf(breakpoint_desc["breakpoint_ins"]))
ins_writer.flush()
}
break
default:
console.error(arch,' not support')
}
});
}
return true
}
/**
* 通过不同的writer来恢复不同的断点
* 重新设置页面保护
* 自己的断点被访问后,恢复断点,设置内存保护
* cmd 2
* @param soft_breakpoint_info 断点信息
* @param writer 不同的writer
* @returns {boolean} 真表示异常处理 假表示异常没被处理
*/
function resume_softbreakpoint_set_pagebreak(soft_breakpoint_info,writer){
let pc_addr = ptr(soft_breakpoint_info['break_addr']);
const size = soft_breakpoint_info['break_len'];
const content = hex2buf(soft_breakpoint_info['ins_content']); // arraybuffer
const break_page_info = soft_breakpoint_info['break_page_info'];
let ins_writer = null
switch(arch){
case "arm64":
ins_writer = new writer(pc_addr);
break
case "arm":
if(check_pc_thumb(pc_addr)){
ins_writer = new breakpoint_desc["thumb_writer"](pc_addr.and(thumb_erase_maskcode))
}
break
default:
console.error(arch,' not support')
}
//恢复原始字节码
Memory.patchCode(pc_addr, size, function (code) {
ins_writer.putBytes(content)
ins_writer.flush()
});
//设置内存保护
rpc.exports.setpageprotect(break_page_info[0],'---')
const send_dict = {};
send_dict['__tag'] = 'resume_soft_breakpoint'
send_dict['addr'] = pc_addr
send(send_dict)
let info_ret = null;
const op = recv('resume_soft_breakpoint_ret', function (value) {
info_ret = value.payload
});
op.wait()
return true
}
/**
*
* @param break_info 断点信息
* @param writer writer
* @param details 异常信息
* @returns {boolean}
*/
function resume_pagebreak_write_softbreakpoint_and_show(break_info,writer,details){
//先调用cmd1的方法 然后把断点信息发送给py脚本
const ret = resume_pagebreak_write_softbreakpoint(break_info, writer);
const data_addr = ptr(break_info['break_addr']);
let lr_addr = ptr(break_info['current_lr']);
const data = buf2hex(rpc.exports.readdata(data_addr, break_info['break_len']));
let _pc = ptr(details['address']);
if(check_pc_thumb(lr_addr)){
_pc = _pc.add(1)
}
const ins = Instruction.parse(_pc);
const symbol = DebugSymbol.fromAddress(_pc);
details['data'] = data
details['symbol'] = symbol
details['ins'] = ins.toString()
details["operands"] = ins["operands"]
details['__tag'] = "show_details"
send(details)
return ret
}
//返回为true false 表示这个异常是否被处理
function handle_cmd(info,details){
const cmd = info['cmd'];
switch (cmd){
case 1:
return resume_pagebreak_write_softbreakpoint(info,breakpoint_desc["writer"])
case 2:
return resume_softbreakpoint_set_pagebreak(info,breakpoint_desc["writer"])
case 3:
return resume_pagebreak_write_softbreakpoint_and_show(info,breakpoint_desc["writer"],details)
case 100:
return false
}
}
rpc.exports = {
getdevicearch(){
//获取程序架构
return Process.arch
},
getplatform(){
//获取平台架构
return Process.platform
},
getpointersize(){
//获取指针长度
return Process.pointerSize
},
getpagesize(){
//获取内存分页大小
return Process.pageSize
},
getmodule(name){
//获取模块基本信息
return Process.findModuleByName(name)
},
setexceptionhandler(){
//设置异常处理handler
Process.setExceptionHandler(function(details){
let break_info = null;
details['__tag'] = "exception"
send(details)
const op = recv('exception_ret', function (value) {
break_info = value.payload
});
op.wait()
return handle_cmd(break_info,details)
})
},
getprotectranges(){
//枚举内存保护标志
return Process.enumerateRanges("---")
},
getexportbyname(so_name,symbol_name){
return Module.getExportByName(so_name,symbol_name)
},
readdata(pointer,len){
//读取数据
return ptr(pointer).readByteArray(len)
},
setpageprotect(addr,flag){
//设置页面内存保护
Memory.protect(ptr(addr),Process.pageSize,flag)
}
}