前文http://bbs.pediy.com/showthread.php?t=194417
正如Android调用JNI本地方法经过有点改 变章所说跟踪代码是可行的,但是跟踪某些代码会出现anr,点击取消,还是不好运,有提高办法吗?回答是有(gdb还没试过,本文只讨论ida)。
下面是我使用 0 * Message("%s = %d\n", GetString(Dword(R2+0x10),-1, ASCSTR_C), R2+0x20)打出的记录
enforceInterface = 1108147904
writeInterfaceToken = 1108151492
writeStrongBinder = 1108152272
transact = 1108144564
lockCanvasNative = 1108185020
nativeDraw = 1108271444
native_getClipBounds = 1108165440
native_measureText = 1108172200
native_drawText = 1108165180
nativeDraw = 1108271444
unlockCanvasAndPost = 1108186532
enforceInterface = 1108147904
writeInterfaceToken = 1108151492
writeStrongBinder = 1108152272
transact = 1108144564
native_get_long = 1108308360
method = 1110009932
native_measureText = 1108172200
getFontMetricsInt = 1108173712
native_measureText = 1108172200
native_measureText = 1108172200
lockCanvasNative = 1108185020
drawText = 1108168304
nativeDraw = 1108271444
native_getClipBounds = 1108165440
native_measureText = 1108172200
native_drawText = 1108165180
nativeDraw = 1108271444
native_getClipBounds = 1108165440
native_measureText = 1108172200
native_drawText = 1108165180
nativeDraw = 1108271444
unlockCanvasAndPost = 1108186532
反复调用然后anr了。
为了改善这种情况。经过仔细查阅IDA文档Edit breakpoint一章,发现
DbgDword
// Get value of program double word (4 bytes) using the debugger memory
// ea - linear address
// returns: the value of the double word. Throws an exception on failure.
// Thread-safe function (may be called only from the main thread and debthread)
long DbgDword (long ea);
GetString
// Get string contents
// ea - linear address
// len - string length. -1 means to calculate the max string length
// type - the string type (one of ASCSTR_... constants)
// Returns: string contents or empty string
string GetString(long ea, long len, long type);
See also GetStringType function.
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <errno.h>
/*
package com.crackme;
public class MainActivity{
private native String crackme(String paramString1, String paramString2);
}
Native的对应函数名要以“Java_”开头,后面依次跟上Java的“package名”、“class名”、“函数名”,中间以下划线“_” 分割,在package名中的“.”也要改为“_”。
此外,关于函数的参数和返回值也有相应的规则。对于Java中的基本类型如int 、double 、char等,在Native端都有相对应的类型来表示,如jint 、jdouble 、jchar 等;其他的对象类型则统统由jobject 来表示(String 是个例外,由于其使用广泛,故在Native代码中有 jstring 这个类型来表示,正如在上例中返回值String 对应到Native代码中的返回值jstring )。而对于Java中的数组,在Native中由jarray 对应,具体到基本类型和一般对象类型的数组则有jintArray 等和jobjectArray 分别对应(String 数组在这里没有例外,同样用jobjectArray 表示)。
还有一点需要注意的是,在JNI的Native函数中,其前两个参数JNIEnv *和jobject 是必需的——前者是一个JNIEnv 结构体的指针是JNI的核心数据,这个结构体中定义了很多JNI的接口函数指针,使开发者可以使用JNI所定义的接口功能;后者指代的是调用这个JNI函数的Java对象,有点类似于C++中的this 指针。在上述两个参数之后,还需要根据Java端的函数声明依次对应添加参数。
在上例中,Java中声明的JNI函数对应命名为:
//Class: com_crackme_MainActivity
//Method: crackme
//Signature: (Ljava/lang/String;)Ljava/lang/String;
jstring Java_com_crackme_MainActivity_crackme(JNIEnv *,jobject,jstring,jstring);
jstring (*crackme)(JNIEnv *,jobject,jstring, jstring) = NULL;
//事先把libcrackme.so放到root/system/lib/目录下
void *filehandle = dlopen("/system/lib/libcrackme.so", RTLD_LAZY);
//(jstring (*)(JNIEnv *,jobject, jstring, jstring))
if(filehandle)
{
crackme = (jstring (*)(JNIEnv *,jobject, jstring, jstring))dlsym(filehandle, "Java_com_crackme_MainActivity_crackme");
if(crackme){
jstring s = crackme(env, obj, a, b);
}
dlclose(filehandle);
filehandle = NULL;
}
*/
typedef void *CRACKME;
//typedef jstring *CRACKME(JNIEnv *,jobject, jstring, jstring);
int main(int argc, char **argv)
{
CRACKME *crackme;
int i = 0;
void *handle;
//其实不能直接这样用jni
handle = dlopen("/home/Sansan/a/libcrackme.so", RTLD_LAZY);
if (!handle) {
printf("%s, %d, NULL == handle. errno = %d, %s\n", __FUNCTION__, __LINE__, errno, strerror(errno));
return -1;
}
crackme = dlsym(handle, "JNI_OnLoad");
if (!crackme) {
printf("%s, %d, NULL == crackme\n", __FUNCTION__, __LINE__);
return -1;
}
printf("%s, %d, crackme = %p\n", __FUNCTION__, __LINE__, crackme);
dlclose(handle);
return 0;
}
int __fastcall sub_80905D1C(int a1, int a2, int a3, int a4)
{
int v4; // r6@1
int v5; // r4@1
int v6; // r7@1
int v7; // r0@1
v4 = a4;
v5 = a1;
v6 = (*(int (**)(void))(*(_DWORD *)a1 + 676))();
v7 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v5 + 676))(v5, v4, 0);
((void (__fastcall *)(_UNKNOWN *, int, int))unk_809055F8)(&unk_80916344, v6, v7);
((void (__fastcall *)(_UNKNOWN *))unk_80905C44)(&unk_80916344);
return (*(int (__fastcall **)(int, _UNKNOWN *))(*(_DWORD *)v5 + 668))(v5, &unk_80916344);
}
int __fastcall sub_809055F8(int a1, int a2, int a3)
{
int v3; // r6@1
int v4; // r4@1
int v5; // r5@1
int result; // r0@1
int v7; // r0@3
int v8; // r7@3
int v9; // r0@3
int v10; // r7@3
int v11; // r3@3
int v12; // [sp+4h] [bp-24h]@3
int v13; // [sp+8h] [bp-20h]@3
int v14; // [sp+Ch] [bp-1Ch]@3
v3 = a3;
v4 = a1;
v5 = a2;
result = ((int (*)(void))unk_809055B4)();
if ( v3 )
{
if ( v5 )
{
v7 = ((int (__fastcall *)(int))strlen_0)(v5);
v13 = v7;
v8 = v7;
v9 = ((int (__fastcall *)(int))strlen_0)(v3);
v10 = v8 + 1;
v14 = v9;
v12 = v9 + 1;
*(_DWORD *)(v4 + 52) = ((int (__fastcall *)(int))malloc_0)(v10);
result = ((int (__fastcall *)(int))malloc_0)(v12);
v11 = *(_DWORD *)(v4 + 52);
*(_DWORD *)(v4 + 56) = result;
if ( v11 )
{
if ( result )
{
((void (__fastcall *)(int, _DWORD, int))memset_0)(v11, 0, v10);
((void (__fastcall *)(_DWORD, _DWORD, int))memset_0)(*(_DWORD *)(v4 + 56), 0, v12);
((void (__fastcall *)(_DWORD, int, int))memcpy_0)(*(_DWORD *)(v4 + 52), v5, v13);
result = ((int (__fastcall *)(_DWORD, int, int))memcpy_0)(*(_DWORD *)(v4 + 56), v3, v14);
}
}
}
}
return result;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: