Android调用JNI本地方法跟踪目标代码

正如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一章,发现

  Low level condition:
        Evaluate the condition on the remote computer. Such conditions are
        faster, especially during remote debugging, because there is no
        network traffic between IDA and the remote computer on each
        breakpoint hit. More details

低级条件,在远程计算机计算条件。这种条件运行更快,特别是在远程调试的时候。详细内容如下:

Low level breakpoint conditions

Low level breakpoint conditions can be used to speed up the debugger. They are evaluated like this:

  - for remote debugging, such a condition is evaluated on the remote
    computer. The following actions are bypassed:
      - copying the breakpoint event to the local computer
      - switching from debthread to the main thread
      - updating internal IDA structures and caches
      - updating the screen
  - for local debugging, such a condition is evaluated at low level.
    The following actions are bypassed:
      - switching from debthread to the main thread
      - updating internal IDA structures and caches
      - updating the screen

In both cases, there is a significant speed up. This improvement imposes some limitations on the breakpoint condition:

  - only IDC expressions can be used for low level conditions
  - only functions marked as 'thread-safe' may be called
  - only entire registers can be accessed (e.g. EAX is ok but AL is not)

Essentially this means that the only available functions are:

  - read/write process registers
  - read/write process memory
  - file i/o
  - auxiliary string and object functions
  - Message() function (for debugging the breakpoint conditions)

Low level breakpoint conditions are available only for Win32, WinCE, Linux, Mac, Android debuggers. 

从中看到对我有影响的就是使用的函数必须带有'thread-safe'字样提示。

 诸如前文使用的

0 * print(GetString(DbgDword(R2+0x10),-1, ASCSTR_C))

"method" == GetString(DbgDword(R2+0x10),-1, ASCSTR_C)

0 * Message("%s = %d\n", GetString(DbgDword(R2+0x10),-1, ASCSTR_C), R2+0x20)

其中DbgDword就是线程安全的,而Dword就不是,如此

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.

就没有

所以报错,不允许。

 

为了找到替代,找到一大圈无果。直到一个一个比较,先比较前几个吧如案例

可以在这个论坛下载2014攻防对抗挑战

 

复制代码
#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;
    
    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;
}
复制代码

 

 条件语句类似这样

'c' == DbgByte(DbgDword(R2+0x10)) && 'r' == DbgByte(1+DbgDword(R2+0x10)) && 'a' == DbgByte(2+DbgDword(R2+0x10)) && 'c' == DbgByte(3+DbgDword(R2+0x10)) && 'k' == DbgByte(4+DbgDword(R2+0x10))

 

跳到目标,如果F5不行需要弄一下。

 

最后F5结果,有神奇F5就是容易点啊,虽说君子善假于物也,依靠工具会产生惰性,分析汇编能力会下降。

复制代码
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))sub_809055F8)(&"Failure", v6, v7);
  ((void (__fastcall *)(_UNKNOWN *))sub_80905C44)(&"Failure");
  return (*(int (__fastcall **)(int, _UNKNOWN *))(*(_DWORD *)v5 + 668))(v5, &"Failure");
}
复制代码

 

复制代码
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;
}
复制代码

 

 

复制代码
int __fastcall sub_809055B4(int a1)
{
  int v1; // r4@1

  v1 = a1;
  if ( *(_DWORD *)(a1 + 52) )
  {
    ((void (*)(void))free)();
    *(_DWORD *)(v1 + 52) = 0;
  }
  if ( *(_DWORD *)(v1 + 56) )
  {
    ((void (*)(void))free)();
    *(_DWORD *)(v1 + 56) = 0;
  }
  memset_0(v1 + 60, 0, 30);
  return memset_0(v1, 0, 50);
}
复制代码

 

接下来的工作分析吧,很常规了。。。

附两个头可以直接导入,使用其中的结构体,但是对于C++方式结构体,即类的不知道怎么导入,记住先倒入依赖的头stddarg.h(jni依赖它)

stdarg.h

 

jni.h

 

然后可以使用其中的结构体了。

有人曾搞成excel但是不知道地址了,临时下载,当时看到下来看是不能传出去的。

 

君子之才华,玉韫珠藏,不可使人易知。邦无道则隐,邦有道则现。君子善假于物也。胆大心细脸皮厚。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值