/
/
保存指令和寄存器环境类:
class
InsAndCtx
{
long
addr;
Instruction ins;
List
<Number> regs;
public
long
getAddr() {
return
addr;
}
public void setAddr(
long
addr) {
this.addr
=
addr;
}
public void setIns(Instruction ins) {
this.ins
=
ins;
}
public Instruction getIns() {
return
ins;
}
public void setRegs(
List
<Number> regs) {
this.regs
=
regs;
}
public
List
<Number> getRegs() {
return
regs;
}
}
/
/
patch类
class
PatchIns{
long
addr;
/
/
patch 地址
String ins;
/
/
patch的指令
public
long
getAddr() {
return
addr;
}
public void setAddr(
long
addr) {
this.addr
=
addr;
}
public String getIns() {
return
ins;
}
public void setIns(String ins) {
this.ins
=
ins;
}
}
/
/
指令栈
private Stack<InsAndCtx> instructions;
/
/
所有需要patch的指令
private
List
<PatchIns> patchs;
/
/
保存指令寄存器环境
public
List
<Number> saveRegs(Backend bk)
{
List
<Number> nb
=
new ArrayList<>();
for
(
int
i
=
0
;i<
29
;i
+
+
)
{
nb.add(bk.reg_read(i
+
Arm64Const.UC_ARM64_REG_X0));
}
nb.add(bk.reg_read(Arm64Const.UC_ARM64_REG_FP));
nb.add(bk.reg_read(Arm64Const.UC_ARM64_REG_LR));
return
nb;
}
/
/
指令hook,每条指令执行前保存环境
public void processBr()
{
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend,
long
address,
int
size,
Object
user) {
Capstone capstone
=
new Capstone(Capstone.CS_ARCH_ARM64,Capstone.CS_MODE_ARM);
byte[] bytes
=
emulator.getBackend().mem_read(address,
4
);
Instruction[] disasm
=
capstone.disasm(bytes,
0
);
InsAndCtx iac
=
new InsAndCtx();
iac.setIns(disasm[
0
]);
iac.setRegs(saveRegs(backend));
iac.setAddr(address);
instructions.push(iac);
do_processbr();
}
@Override
public void onAttach(UnHook unHook) {
System.out.println(
"attach"
);
}
@Override
public void detach() {
System.out.println(
"detach"
);
}
},module.base
+
start, module.base
+
end,null);
}
/
/
指令栈回溯,根据处理结果,生成patchIns,供最后统一patch
public void do_processbr()
{
Instruction ins
=
instructions.peek().getIns();
if
(ins.getMnemonic().equals(
"br"
) && ins.getOpStr().equals(
"x9"
))
{
boolean finish
=
false;
long
base
=
-
1
;
long
listoffset
=
-
1
;
long
cond1
=
-
1
;
long
cond2
=
-
1
;
String cond
=
"";
long
addinstaddr
=
-
1
;
long
brinsaddr
=
instructions.peek().getAddr()
-
module.base;
long
selectaddr
=
-
1
;
long
ldaaddr
=
-
1
;
try
{
while
(!finish && !instructions.empty())
{
instructions.pop();
ins
=
instructions.peek().getIns();
if
(ins.getMnemonic().toLowerCase(Locale.ROOT).equals(
"add"
))
{
String[] split
=
ins.getOpStr().split(
","
);
if
(split.length
=
=
3
)
{
if
(split[
0
].toLowerCase(Locale.ROOT).trim().equals(
"x9"
) && split[
1
].toLowerCase(Locale.ROOT).trim().equals(
"x9"
))
{
String reg
=
split[
2
].trim().toLowerCase(Locale.ROOT);
base
=
getRegValue(reg,instructions.peek().getRegs()).longValue();
addinstaddr
=
instructions.peek().getAddr()
-
module.base;
}
else
{
break
;
}
}
else
{
break
;
}
}
if
(ins.getMnemonic().toLowerCase(Locale.ROOT).equals(
"ldr"
))
{
String[] sp
=
ins.getOpStr().toLowerCase().split(
","
);
if
(sp.length
=
=
3
)
{
if
(sp[
0
].trim().toLowerCase(Locale.ROOT).equals(
"x9"
) && sp[
2
].trim().toLowerCase(Locale.ROOT).equals(
"x9]"
))
{
String reg
=
sp[
1
].toLowerCase(Locale.ROOT).trim().substring(
1
);
listoffset
=
getRegValue(reg,instructions.peek().getRegs()).longValue()
-
module.base;
ldaaddr
=
instructions.peek().getAddr()
-
module.base;
}
}
}
if
(ins.getMnemonic().trim().toLowerCase(Locale.ROOT).equals(
"csel"
))
{
String[] sp
=
ins.getOpStr().toLowerCase(Locale.ROOT).split(
","
);
if
(sp.length
=
=
4
)
{
cond
=
sp[
3
].trim();
if
(sp[
0
].trim().equals(
"x9"
))
{
String reg1
=
sp[
1
].trim();
String reg2
=
sp[
2
].trim();
cond1
=
getRegValue(reg1,instructions.peek().getRegs()).longValue();
cond2
=
getRegValue(reg2,instructions.peek().getRegs()).longValue();
selectaddr
=
instructions.peek().getAddr()
-
module.base;
}
}
}
if
(ins.getMnemonic().trim().toLowerCase(Locale.ROOT).equals(
"cmp"
))
{
if
(base
=
=
-
1
|| listoffset
=
=
-
1
|| cond1
=
=
-
1
|| cond2
=
=
-
1
|| cond.equals("") || addinstaddr
=
=
-
1
|| ldaaddr
=
=
-
1
|| selectaddr
=
=
-
1
)
{
break
;
}
else
{
long
offset1
=
base
+
readInt64(emulator.getBackend(), module.base
+
listoffset
+
cond1)
-
module.base;
long
offset2
=
base
+
readInt64(emulator.getBackend(),module.base
+
listoffset
+
cond2)
-
module.base;
if
( brinsaddr
-
addinstaddr !
=
4
)
{
System.out.println(
"add ins and br ins gap more than 4 size,may make mistake"
);
}
String condBr
=
"b"
+
cond.toLowerCase(Locale.ROOT)
+
" 0x"
+
Integer.toHexString((
int
) (offset1
-
addinstaddr));
String br
=
"b 0x"
+
Integer.toHexString((
int
)(offset2
-
brinsaddr));
PatchIns pi1
=
new PatchIns();
pi1.setAddr(addinstaddr);
pi1.setIns(condBr);
patchs.add(pi1);
PatchIns pi2
=
new PatchIns();
pi2.setAddr(brinsaddr);
pi2.setIns(br);
patchs.add(pi2);
PatchIns pi3
=
new PatchIns();
pi3.setAddr(selectaddr);
pi3.setIns(
"nop"
);
patchs.add(pi3);
PatchIns pi4
=
new PatchIns();
pi4.setAddr(ldaaddr);
pi4.setIns(
"nop"
);
patchs.add(pi4);
finish
=
true;
}
}
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}
/
/
遍历patch表,执行patch,生成新的so,使用Ketstone将汇编转为机器码。
public void patch()
{
try
{
File
f
=
new
File
(inName);
FileInputStream fis
=
new FileInputStream(f);
byte[] data
=
new byte[(
int
) f.length()];
fis.read(data);
fis.close();
for
(PatchIns pi:patchs)
{
System.out.println(
"procrss addr:"
+
Integer.toHexString((
int
) pi.addr)
+
",code:"
+
pi.getIns());
Keystone ks
=
new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian);
KeystoneEncoded assemble
=
ks.assemble(pi.getIns());
for
(
int
i
=
0
;i<assemble.getMachineCode().length;i
+
+
)
{
data[(
int
) pi.addr
+
i]
=
assemble.getMachineCode()[i];
}
}
File
fo
=
new
File
(outName);
FileOutputStream fos
=
new FileOutputStream(fo);
fos.write(data);
fos.flush();
fos.close();
System.out.println(
"finish"
);
}
catch (Exception e)
{
e.printStackTrace();
}
}