Stalker.follow中的transform中的Instruction的属性
此处介绍Stalker.follow
中transform
中的指令
=instruction
的属性的详情:
Instruction有哪些属性
参考官网文档:Frida的Instruction(和其他相关资料),可以总结出:
- Instruction的属性
address
next
size
mnemonic
opStr
operands
regsRead
regsWritten
groups
toString()
regsAccessed
toJSON()
如何打印Instruction的属性
打印对应的属性值的代码:
console.log("instruction: address=" + instruction.address
+ ",next=" + instruction.next
+ ",size=" + instruction.size
+ ",mnemonic=" + instruction.mnemonic
+ ",opStr=" + instruction.opStr
+ ",operands=" + JSON.stringify(instruction.operands)
+ ",regsRead=" + JSON.stringify(instruction.regsRead)
+ ",regsWritten=" + JSON.stringify(instruction.regsWritten)
+ ",groups=" + JSON.stringify(instruction.groups)
+ ",toString()=" + instruction.toString()
);
输出效果:
instruction: address=0x10f4ecef4,next=0x4,size=4,mnemonic=ldr,opStr=x0, #0x10f4ecf78,operands=[{"type":"reg","value":"x0","access":"w"},{"type":"imm","value":"4551790456","access":"r"}],regsRead=[],regsWritten=[],groups=[],toString()=ldr x0, #0x10f4ecf78
[0x10f4ecef4] ldr x0, #0x10f4ecf78
instruction: address=0x10f4ecef8,next=0x4,size=4,mnemonic=bl,opStr=#0x1091a500c,operands=[{"type":"imm","value":"4447686668","access":"r"}],regsRead=[],regsWritten=["lr"],groups=["call","jump","branch_relative"],toString()=bl #0x1091a500c
[0x10f4ecef8] bl #0x1091a500c
FridaUtil的printInstructionInfo
以及后续新版中,加上:regsAccessed
、toJSON()
后,经过整理,已提取到工具类函数中:
https://github.com/crifan/JsFridaUtil/blob/main/frida/FridaUtil.js
中的:
static printInstructionInfo(instruction){
// Instruction: address=0x252c0edf8,toString()=br x10,next=0x4,size=4,mnemonic=br,opStr=x10,operands=[{"type":"reg","value":"x10","access":"r"}],regsAccessed={"read":["x10"],"written":[]},regsRead=[],regsWritten=[],groups=["jump"],toJSON()={"address":"0x252c0edf8","next":"0x4","size":4,"mnemonic":"br","opStr":"x10","operands":[{"type":"reg","value":"x10","access":"r"}],"regsAccessed":{"read":["x10"],"written":[]},"regsRead":[],"regsWritten":[],"groups":["jump"]}
console.log("Instruction: address=" + instruction.address
+ ",toString()=" + instruction.toString()
+ ",toJSON()=" + JSON.stringify(instruction.toJSON())
// + ",next=" + instruction.next
// + ",size=" + instruction.size
// + ",mnemonic=" + instruction.mnemonic
// + ",opStr=" + instruction.opStr
// + ",operands=" + JSON.stringify(instruction.operands)
// + ",regsAccessed=" + JSON.stringify(instruction.regsAccessed)
// + ",regsRead=" + JSON.stringify(instruction.regsRead)
// + ",regsWritten=" + JSON.stringify(instruction.regsWritten)
// + ",groups=" + JSON.stringify(instruction.groups)
)
}
以及之前的某次输出的效果是:
Instruction: address=0x252c0eca4,toString()=stp x20, x19, [sp, #0x40],next=0x4,size=4,mnemonic=stp,opStr=x20, x19, [sp, #0x40],operands=[{"type":"reg","value":"x20","access":"r"},{"type":"reg","value":"x19","access":"r"},{"type":"mem","value":{"base":"sp","disp":64},"access":"rw"}],regsAccessed={"read":["x20","x19","sp"],"written":[]},regsRead=[],regsWritten=[],groups=[],toJSON()={"address":"0x252c0eca4","next":"0x4","size":4,"mnemonic":"stp","opStr":"x20, x19, [sp, #0x40]","operands":[{"type":"reg","value":"x20","access":"r"},{"type":"reg","value":"x19","access":"r"},{"type":"mem","value":{"base":"sp","disp":64},"access":"rw"}],"regsAccessed":{"read":["x20","x19","sp"],"written":[]},"regsRead":[],"regsWritten":[],"groups":[]}
供参考。
Instruction的属性的来源
而这些属性的来源:
- 主要是
Capstone
- 其次是
Frida
内部
下面摘录其相关的核心代码:
capstone/Capstone.java
protected static class _cs_insn extends Structure {
// instruction ID.
public int id;
// instruction address.
public long address;
// instruction size.
public short size;
// machine bytes of instruction.
public byte[] bytes;
// instruction mnemonic. NOTE: irrelevant for diet engine.
public byte[] mnemonic;
// instruction operands. NOTE: irrelevant for diet engine.
public byte[] op_str;
// detail information of instruction.
public _cs_detail.ByReference cs_detail;
...
public static class CsInsn {
private Pointer csh;
private CS cs;
private _cs_insn raw;
private int arch;
// instruction ID.
public int id;
// instruction address.
public long address;
// instruction size.
public short size;
// Machine bytes of this instruction, with number of bytes indicated by size above
public byte[] bytes;
// instruction mnemonic. NOTE: irrelevant for diet engine.
public String mnemonic;
// instruction operands. NOTE: irrelevant for diet engine.
public String opStr;
// list of all implicit registers being read.
public short[] regsRead;
// list of all implicit registers being written.
public short[] regsWrite;
// list of semantic groups this instruction belongs to.
public byte[] groups;
public OpInfo operands;
capstone/__init__.py
中相关核心代码:
class _cs_insn(ctypes.Structure):
_fields_ = (
('id', ctypes.c_uint),
('alias_id', ctypes.c_uint64),
('address', ctypes.c_uint64),
('size', ctypes.c_uint16),
('bytes', ctypes.c_ubyte * 24),
('mnemonic', ctypes.c_char * 32),
('op_str', ctypes.c_char * 160),
('is_alias', ctypes.c_bool),
('usesAliasDetails', ctypes.c_bool),
('illegal', ctypes.c_bool),
('detail', ctypes.POINTER(_cs_detail)),
)
...
# Python-style class to disasm code
class CsInsn(object):
def __init__(self, cs, all_info):
self._raw = copy_ctypes(all_info)
self._cs = cs
if self._cs._detail and not self.is_invalid_insn():
# save detail
self._raw.detail = ctypes.pointer(all_info.detail._type_())
ctypes.memmove(ctypes.byref(self._raw.detail[0]), ctypes.byref(all_info.detail[0]),
ctypes.sizeof(type(all_info.detail[0])))
def __repr__(self):
return '<CsInsn 0x%x [%s]: %s %s>' % (self.address, self.bytes.hex(), self.mnemonic, self.op_str)
# return if the instruction is invalid
def is_invalid_insn(self):
arch = self._cs.arch
if arch == CS_ARCH_EVM:
return self.id == evm.EVM_INS_INVALID
else:
return self.id == 0
# return instruction's ID.
@property
def id(self):
return self._raw.id
# return instruction's address.
@property
def address(self):
return self._raw.address
# return instruction's size.
@property
def size(self):
return self._raw.size
# return instruction's is_alias flag
@property
def is_alias(self):
return self._raw.is_alias
# return instruction's illegal flag
# Set if instruction can be decoded but is invalid
# due to context or illegal operands.
@property
def illegal(self):
return self._raw.illegal
# return instruction's alias_id
@property
def alias_id(self):
return self._raw.alias_id
# return instruction's flag if it uses alias details
@property
def uses_alias_details(self):
return self._raw.usesAliasDetails
# return instruction's machine bytes (which should have @size bytes).
@property
def bytes(self):
return bytearray(self._raw.bytes)[:self._raw.size]
# return instruction's mnemonic.
@property
def mnemonic(self):
if self._cs._diet:
# Diet engine cannot provide @mnemonic.
raise CsError(CS_ERR_DIET)
return self._raw.mnemonic.decode('ascii')
# return instruction's operands (in string).
@property
def op_str(self):
if self._cs._diet:
# Diet engine cannot provide @op_str.
raise CsError(CS_ERR_DIET)
return self._raw.op_str.decode('ascii')
# return list of all implicit registers being read.
@property
def regs_read(self):
if self.is_invalid_insn():
raise CsError(CS_ERR_SKIPDATA)
if self._cs._diet:
# Diet engine cannot provide @regs_read.
raise CsError(CS_ERR_DIET)
if self._cs._detail:
return self._raw.detail.contents.regs_read[:self._raw.detail.contents.regs_read_count]
raise CsError(CS_ERR_DETAIL)
# return list of all implicit registers being modified
@property
def regs_write(self):
if self.is_invalid_insn():
raise CsError(CS_ERR_SKIPDATA)
if self._cs._diet:
# Diet engine cannot provide @regs_write
raise CsError(CS_ERR_DIET)
if self._cs._detail:
return self._raw.detail.contents.regs_write[:self._raw.detail.contents.regs_write_count]
raise CsError(CS_ERR_DETAIL)
# return list of semantic groups this instruction belongs to.
@property
def groups(self):
if self.is_invalid_insn():
raise CsError(CS_ERR_SKIPDATA)
if self._cs._diet:
# Diet engine cannot provide @groups
raise CsError(CS_ERR_DIET)
if self._cs._detail:
return self._raw.detail.contents.groups[:self._raw.detail.contents.groups_count]
raise CsError(CS_ERR_DETAIL)
# return whether instruction has writeback operands.
@property
def writeback(self):
if self.is_invalid_insn():
raise CsError(CS_ERR_SKIPDATA)
if self._cs._diet:
# Diet engine cannot provide @writeback.
raise CsError(CS_ERR_DIET)
if self._cs._detail:
return self._raw.detail.contents.writeback
raise CsError(CS_ERR_DETAIL)
frida-gum/bindings/gumjs/gumquickinstruction.c
frida-gum/bindings/gumjs/gumquickinstruction.c at main · frida/frida-gum
的相关核心代码:
static const JSCFunctionListEntry gumjs_instruction_entries[] =
{
JS_CGETSET_DEF ("address", gumjs_instruction_get_address, NULL),
JS_CGETSET_DEF ("next", gumjs_instruction_get_next, NULL),
JS_CGETSET_DEF ("size", gumjs_instruction_get_size, NULL),
JS_CGETSET_DEF ("mnemonic", gumjs_instruction_get_mnemonic, NULL),
JS_CGETSET_DEF ("opStr", gumjs_instruction_get_op_str, NULL),
JS_CGETSET_DEF ("operands", gumjs_instruction_get_operands, NULL),
JS_CGETSET_DEF ("regsAccessed", gumjs_instruction_get_regs_accessed, NULL),
JS_CGETSET_DEF ("regsRead", gumjs_instruction_get_regs_read, NULL),
JS_CGETSET_DEF ("regsWritten", gumjs_instruction_get_regs_written, NULL),
JS_CGETSET_DEF ("groups", gumjs_instruction_get_groups, NULL),
JS_CFUNC_DEF ("toString", 0, gumjs_instruction_to_string),
JS_CFUNC_DEF ("toJSON", 0, gumjs_instruction_to_json),
};