Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mar-v-in/7be2290a9483939328ad8f0445d8aed8 to your computer and use it in GitHub Desktop.
Save mar-v-in/7be2290a9483939328ad8f0445d8aed8 to your computer and use it in GitHub Desktop.
Android ART native method call tracer for frida.re
{
/**
* Called synchronously when about to call _ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use Memory.readUtf8String(args[0]) if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter: function (log, args, state) {
function StringId(ptr) { // struct
try {
return {
'string_data_off_': Memory.readU32(ptr)
};
} catch (err) {
log("Error creating StringId at "+ptr+": "+err);
return null;
}}
function TypeId(ptr) { // struct
try {
return {
'descriptor_idx_': Memory.readU32(ptr)
};
} catch (err) {
log("Error creating TypeId at "+ptr+": "+err);
return null;
}}
function MethodId(ptr) { // struct
try {
return {
'class_idx_': Memory.readU16(ptr),
'proto_idx_': Memory.readU16(ptr.add(2)),
'name_idx_': Memory.readU32(ptr.add(4))
};
} catch (err) {
log("Error creating MethodId at "+ptr+": "+err);
return null;
}}
function ClassDef(ptr) { // struct
try {
return {
'class_idx_': Memory.readU16(ptr),
'access_flags_': Memory.readU32(ptr.add(4)),
'superclass_idx_': Memory.readU16(ptr.add(8)),
'interfaces_off_': Memory.readU32(ptr.add(12)),
'source_file_idx_': Memory.readU32(ptr.add(16)),
'annotations_off_': Memory.readU32(ptr.add(20)),
'class_data_off_': Memory.readU32(ptr.add(24)),
'static_values_off_': Memory.readU32(ptr.add(28)),
};
} catch (err) {
log("Error creating ClassDef at "+ptr+": "+err);
}}
function DexFileHeader(ptr) { // struct
try {
return {
'magic_': Memory.readByteArray(ptr, 8),
'checksum_': Memory.readU32(ptr.add(8)),
'signature_': Memory.readByteArray(ptr.add(12), 20),
'file_size_': Memory.readU32(ptr.add(32)),
'header_size_': Memory.readU32(ptr.add(36)),
'string_ids_size_': Memory.readU32(ptr.add(56))
};
} catch (err) {
log("Error creating DexFileHeader at "+ptr+": "+err);
return null;
}}
function DexFile(ptr) { // class
try {
var begin_ = Memory.readPointer(ptr.add(4));
var size_ = Memory.readU32(ptr.add(8));
//var location_ = Memory.readPointer(ptr.add(12));
var location_checksum_ = Memory.readU32(ptr.add(24));
var mem_map_ = Memory.readPointer(ptr.add(28));
var header_ = Memory.readPointer(ptr.add(32));
var string_ids_ = Memory.readPointer(ptr.add(36));
var type_ids_ = Memory.readPointer(ptr.add(40));
var field_ids_ = Memory.readPointer(ptr.add(44));
var method_ids_ = Memory.readPointer(ptr.add(48));
var proto_ids_ = Memory.readPointer(ptr.add(52));
var class_defs_ = Memory.readPointer(ptr.add(56));
function GetHeader() {
return DexFileHeader(header_);
}
function GetMethodId(idx) {
return MethodId(method_ids_.add(idx*8));
}
function GetClassDef(idx) {
return ClassDef(class_defs_.add(idx*32));
}
function GetTypeId(idx) {
return TypeId(type_ids_.add(idx*4));
}
function NumStringIds() {
return GetHeader().string_ids_size_;
}
function GetStringId(idx) {
if (idx >= NumStringIds()) {
log(idx + " overflows "+NumStringIds());
return null;
}
return StringId(string_ids_.add(idx*4));
}
function GetStringData(string_id) {
if (string_id == null) return null;
return Memory.readUtf8String(begin_.add(string_id.string_data_off_).add(1));
}
function StringDataByIdx(idx) {
return GetStringData(GetStringId(idx));
}
function GetMethodName(method_id) {
return StringDataByIdx(method_id.name_idx_);
}
function GetTypeDescriptor(type_id) {
return StringDataByIdx(type_id.descriptor_idx_);
}
return {
"GetMethodId": GetMethodId,
"GetTypeId": GetTypeId,
"GetStringId": GetStringId,
"GetClassDef": GetClassDef,
"GetTypeDescriptor": GetTypeDescriptor,
"GetMethodName": GetMethodName
};
} catch (err) {
log("Error creating DexFile at "+ptr+": "+err);
return null;
}}
function DexCache(ptr) { // class
var dex_file_ = Memory.readPointer(ptr.add(32));
function GetDexFile() {
return DexFile(dex_file_);
}
return {
"GetDexFile": GetDexFile
};
}
function Class(ptr) { // class
var dex_cache_ = Memory.readPointer(ptr.add(16));
var dex_class_def_index_ = Memory.readU32(declClass.add(88));
function GetDexCache() {
return DexCache(dex_cache_);
}
function GetDexClassDefIndex() {
return dex_class_def_index_;
}
function GetDexFile() {
return GetDexCache().GetDexFile();
}
function GetClassDef() {
return GetDexFile().GetClassDef(GetDexClassDefIndex());
}
function GetDescriptor() {
var dex_file = GetDexFile();
var type_id = dex_file.GetTypeId(GetClassDef().class_idx_);
return dex_file.GetTypeDescriptor(type_id);
}
return {
"GetDexCache": GetDexCache,
"GetDescriptor": GetDescriptor
};
}
function ArtMethod(ptr) { // class
var declaring_class_ = Memory.readPointer(ptr);
var dex_method_index_ = Memory.readU32(ptr.add(20));
function GetDeclaringClass() {
return Class(declaring_class_);
}
function GetDexCache() {
return GetDeclaringClass().GetDexCache();
}
function GetDexFile() {
return GetDexCache().GetDexFile();
}
function GetDexMethodIndex() {
return dex_method_index_;
}
function GetName() {
var dex_method_idx = GetDexMethodIndex();
var dex_file = GetDexFile();
var name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
return name;
}
return {
"GetName": GetName,
"GetDeclaringClass": GetDeclaringClass
};
}
function readArtString(s) {
return Memory.readUtf16String(s.add(16), Memory.readS32(s.add(8)));
}
var artMethod = args[0];
var declClass = Memory.readPointer(artMethod);
var declClassNameString = Memory.readPointer(declClass.add(28));
try {
var artMethod = ArtMethod(args[0]);
log(artMethod.GetDeclaringClass().GetDescriptor() + "->" + artMethod.GetName());
} catch (err) {
log(err);
}
},
/**
* Called synchronously when about to return from _ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave: function (log, retval, state) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment