-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathRChainer.lua
406 lines (369 loc) · 13.1 KB
/
RChainer.lua
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
function printChain(pre, u)
if u.offset == nil then
return u.value
else
local ret = ''
for offset, v in pairs(u.offset) do
table.insert(l_table_down2, offset)
ret = ret .. '\n\n' ..
printChain(
pre ..
string.format(' -> 0x%X + 0x%X', u.value, offset),
v)
end
if ret ~= '' then ret = ret:sub(3) end
return ret
end
end
function S_Pointer(t_So, t_Offset, _bit)
local function getRanges()
local ranges = {}
local t = gg.getRangesList('^/data/*.so*$')
for i, v in pairs(t) do
if v.type:sub(2, 2) == 'w' then table.insert(ranges, v) end
end
return ranges
end
local function Get_Address(N_So, Offset, ti_bit)
local ti = gg.getTargetInfo()
local S_list = getRanges()
local t = {}
local _t
local _S = nil
if ti_bit then
_t = 32
else
_t = 4
end
for i in pairs(S_list) do
local _N = S_list[i].internalName:gsub('^.*/', '')
if N_So[1] == _N and N_So[2] == S_list[i].state then
_S = S_list[i]
break
end
end
if _S then
t[#t + 1] = {}
t[#t].address = _S.start + Offset[1]
t[#t].flags = _t
if #Offset ~= 1 then
for i = 2, #Offset do
local S = gg.getValues(t)
t = {}
for _ in pairs(S) do
if not ti.x64 then
S[_].value = S[_].value & 0xFFFFFFFF
end
t[#t + 1] = {}
t[#t].address = S[_].value + Offset[i]
t[#t].flags = _t
end
end
end
_S = t[#t].address
end
return _S
end
local _A = string.format('0x%X', Get_Address(t_So, t_Offset, _bit))
return _A
end
local ti = gg.getTargetInfo()
local x64 = ti.x64
if gg.getResultsCount() ~= 1 then
print('当前搜索列表不为1')
os.exit()
end
local ac_ = gg.getResults(1)[1]
local ac_flags = ac_.flags
local ac_value = ac_.value
local depth, minOffset, maxOffset, level, out
function loadChain(lvl, p)
local fix, mino, maxo, lev = not x64, minOffset, maxOffset, level
for k = lvl, 1, -1 do
local levk, p2, stop = lev[k], {}, true
for j, u in pairs(p) do
if u.offset == nil then
u.offset = {}
if fix then u.value = u.value & 0xFFFFFFFF end
for i, v in ipairs(levk) do
local offset = v.address - u.value
if offset >= mino and offset <= maxo then
u.offset[offset], p2[v], stop = v, v, false
end
end
end
end
if stop then break end
p = p2
end
end
function getRanges()
local archs = {
[0x3] = 'x86',
[0x28] = 'ARM',
[0x3E] = 'x86-64',
[0xB7] = 'AArch64'
}
local ranges = {}
local t = gg.getRangesList('^/data/*.so*$')
local arch = 'unknown'
for i, v in ipairs(t) do
if v.type:sub(2, 2) == '-' then
local t = gg.getValues({
{address = v.start, flags = gg.TYPE_DWORD},
{address = v.start + 0x12, flags = gg.TYPE_WORD}
})
if t[1].value == 0x464C457F then
arch = archs[t[2].value]
if arch == nil then arch = 'unknown' end
end
end
if v.type:sub(2, 2) == 'w' then
v.arch = arch
table.insert(ranges, v)
end
end
return ranges
end
local ranges = getRanges()
gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_ALLOC | gg.REGION_C_DATA |
gg.REGION_C_BSS | gg.REGION_ANONYMOUS)
local cfg_file = gg.getFile() .. '.cfg'
local chunk = loadfile(cfg_file)
local cfg = nil
if chunk ~= nil then cfg = chunk() end
if cfg == nil then cfg = {} end
local pkg = gg.getTargetPackage()
if pkg == nil then pkg = 'none' end
gg.setVisible(false)
while true do
local def = cfg[pkg]
if def == nil then def = {3, 0, 256} end
local p = gg.prompt({'深度', '最小偏移量', '最大偏移量'}, def,
{'number', 'number', 'number'})
if p == nil then
gg.setVisible(true)
os.exit()
end
cfg[pkg] = p
gg.saveVariable(cfg, cfg_file)
depth = p[1]
minOffset = tonumber(p[2])
maxOffset = tonumber(p[3])
level, out = {}, {}
local old = gg.getResults(100000)
local x = os.clock()
for lvl = 0, depth do
if lvl > 0 then
local t = gg.getResults(100000)
level[lvl] = t
gg.toast(lvl .. ' from ' .. depth)
gg.internal3(maxOffset)
end
for m, r in ipairs(ranges) do
local p = gg.getResults(100000, 0, r.start, r['end'])
if #p > 0 then
gg.removeResults(p)
loadChain(lvl, p)
p.map = r
table.insert(out, p)
end
end
if gg.getResultsCount() == 0 then break end
end
gg.loadResults(old)
-- 入表
t_table = {}
for j, p in ipairs(out) do
for i, u in ipairs(p) do
local l_table_down1 = {}
table.insert(t_table, l_table_down1)
table.insert(l_table_down1, string.format('%s',
p.map.internalName:gsub(
'^.*/', '')))
table.insert(l_table_down1, string.format('%s', p.map.state))
l_table_down2 = {}
table.insert(t_table, l_table_down2)
table.insert(l_table_down2, u.address - p.map.start)
printChain(string.format('%s + 0x%X [0x%X]',
p.map.internalName:gsub('^.*/', ''),
u.address - p.map.start, u.address), u)
end
end
gg.toast("正在校验" .. #t_table .. "条链路,请稍候")
-- 检验
last_table = {}
for i = 1, #t_table, 2 do
local t = t_table[i]
local tt = t_table[i + 1]
local ttt = S_Pointer(t, tt, true)
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value ==
ac_value then
table.insert(last_table, t)
table.insert(last_table, tt)
gg.toast("第" .. string.format('%s', (i + 1) / 2) ..
"条链路可用")
end
end
local chain = ''
if #last_table == 0 then chain = '\n\n没有结果' end
gg.toast("已找到" .. #last_table .. "条链路")
-- 重现链路
for i = 1, #last_table, 2 do
chain = chain .. "\n\n" .. string.format('%s', (i + 1) / 2) .. ":" ..
string.format('%s', last_table[i][1]) .. " + " ..
string.format('0x%X', last_table[i + 1][1])
for j = 2, #last_table[i + 1] do
chain = chain .. string.format(' -> 0x%X', last_table[i + 1][j])
end
chain = chain .. " = " .. string.format('%s', ac_value)
end
x = string.format('%.2f', os.clock() - x)
print(depth, minOffset, maxOffset, x)
local chains = #last_table / 2
p = gg.alert('在' .. x .. '秒内找到了' .. chains .. '条链路 (' ..
depth .. ', ' .. minOffset .. ', ' .. maxOffset .. '):' ..
chain, '保存', '重试', '退出')
if p == 1 then break end
if p ~= 2 then
print(last_table)
print(chain)
gg.setVisible(true)
os.exit()
end
end
function main(last_table, ac_flags, ac_value, control_str)
for i = 1, #last_table do
local t = last_table[i][1]
local tt = last_table[i][2]
local ttt = S_Pointer(t, tt, true)
if control_str == "==" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value ==
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false, gg.SIGN_EQUAL, ttt,
ttt)
end
elseif control_str == "~=" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value ~=
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false, gg.SIGN_NOT_EQUAL,
ttt, ttt)
end
elseif control_str == ">" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value >
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false,
gg.SIGN_GREATER_OR_EQUAL, ttt, ttt)
end
elseif control_str == ">=" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value >=
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false,
gg.SIGN_GREATER_OR_EQUAL, ttt, ttt)
end
elseif control_str == "<" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value <
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false,
gg.SIGN_LESS_OR_EQUAL, ttt, ttt)
end
elseif control_str == "<=" then
if gg.getValues({{address = ttt, flags = ac_flags}})[1].value <=
ac_value then
control_flag = true
gg.searchNumber(ac_value, ac_flags, false,
gg.SIGN_LESS_OR_EQUAL, ttt, ttt)
end
end
if control_flag then
li_str = "\n{{"
for l, m in ipairs(t) do
li_str = li_str .. "'" .. string.format('%s', m) .. "',"
end
li_str = li_str .. "},{"
for l, m in ipairs(tt) do
li_str = li_str .. string.format('0x%X', m) .. ","
end
li_str = li_str .. "}}\n\n"
print("序号: " .. i)
print(gg.getValues({{address = ttt, flags = ac_flags}})[1])
print(li_str)
end
end
end
-- 文件名
local script = gg.getFile():gsub('[^/]*$', '') .. ti.packageName
for i = 1, 1000 do
local f = io.open(script .. i .. "-" .. string.format('%s', depth) .. "-" ..
string.format('%s', minOffset) .. "-" ..
string.format('%s', maxOffset) .. '.lua')
if f == nil then
script = script .. i .. "-" .. string.format('%s', depth) .. "-" ..
string.format('%s', minOffset) .. "-" ..
string.format('%s', maxOffset) .. '.lua';
break
end
f:close()
end
function Con_choise()
local control_str_T = {"==", "~=", ">", ">=", "<", "<="}
local control_str_num = gg.choice(control_str_T, 1,
"选择合适的判断条件,取消则选取默认值")
if control_str_num == nil then control_str_num = 1 end
local control_str = control_str_T[control_str_num]
ac_value_S = gg.prompt({
"当前判断条件为: " .. string.format('%s', control_str) ..
"\n当前默认值为: " .. string.format('%s', ac_value) ..
"\n请输入合适的判断值,取消则返回上一步"
}, {[1] = ac_value}, {[1] = "number"})
if ac_value_S == nil or ac_value_S[1] == "" then Con_choise() end
ac_value = tonumber(ac_value_S[1])
return control_str, ac_value
end
local control_str, ac_value = Con_choise()
local p = gg.prompt({'输出文件'}, {script}, {'file'})
if p ~= nil then
script = p[1]
code = ''
local cpi = {}
for i, u in ipairs({S_Pointer, main}) do cpi[i] = debug.getinfo(u) end
local n = 0
for line in io.lines(gg.getFile()) do
n = n + 1
for i, u in ipairs(cpi) do
if n >= u.linedefined and n <= u.lastlinedefined then
code = code .. '\n' .. line
break
end
end
end
-- 拼接
code = code .. "\n\nlocal last_table = {"
for i = 1, #last_table, 2 do
code = code .. "\n\t{{"
for l, m in ipairs(last_table[i]) do
code = code .. "'" .. string.format('%s', m) .. "',"
end
code = code .. "},{"
for l, m in ipairs(last_table[i + 1]) do
code = code .. string.format('0x%X', m) .. ","
end
code = code .. "}},"
end
code = code .. "\n}\nlocal ac_flags = " .. string.format('%s', ac_flags) ..
"\nlocal ac_value = " .. string.format('%s', ac_value) ..
"\nlocal control_str = '" .. string.format('%s', control_str) ..
"'"
code = code .. '\n\nmain(last_table, ac_flags, ac_value, control_str)\n'
-- 写入
local f = io.open(script, 'w+')
f:write(code)
f:close()
gg.toast("保存成功")
end
gg.setVisible(true)