首页
社区
课程
招聘
[原创]Android调用JNI本地方法跟踪目标代码
发表于: 2014-11-14 13:39 9778

[原创]Android调用JNI本地方法跟踪目标代码

2014-11-14 13:39
9778

前文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期)

上传的附件:
收藏
免费 3
支持
分享
最新回复 (2)
雪    币: 236
活跃值: (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
强,弱弱的问下,那个native函数表的顺序可能每个程序变得不同么,如果加壳可不可以在这方面做些处理。
2014-11-17 10:27
0
雪    币: 839
活跃值: (2832)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
3
还是不错的,我把头文件都保存了。感谢分享
2014-12-4 01:53
0
游客
登录 | 注册 方可回帖
返回
//