1. 拿到52pojie的反调试挑战apk

链接: https://www.52pojie.cn/thread-742686-1-1.html 的附件中

2. 项目进行安装,点开app,同时挑战成功,不慌

3. 使用IDA attach到目的进程观察,发现app立刻闪退,证明app必然存在反调试逻辑

4. apk拖入到JEB中观察到,有调用到一个native函数

public class MainActivity extends AppCompatActivity {
@Override // android.support.v7.app.AppCompatActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(0x7F04001B); // layout:activity_main
Toast.makeText(this, myJNI.checkport(), 0).show();
}
} public class myJNI {
static {
System.loadLibrary("six");
} public static native String checkport() {
}
}

那么基本定位到应该是在so层做了这些处理

5. 将apk解压开拿到libsix.so,并通过IDA进行反汇编分析

1. 在导出表中搜索checkport,发现没有,说明是动态注册的
2. 搜索JNI_OnLoad, F5查看反编译代码
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env; // [sp+4h] [bp-14h] BYREF _android_log_print(4, "JNI_LOG", byte_C860B588);
env = 0;
if ( !(*vm)->GetEnv(vm, (void **)&env, 65540) )
{
dword_C860D004 = (int)(*env)->FindClass(env, "demo2/jni/com/myapplication/myJNI");
SearchObjProcess();
if ( dword_C860D004 )
{
if ( (*env)->RegisterNatives(env, (jclass)dword_C860D004, (const JNINativeMethod *)off_C860CE44, 1) >= 0 )
{
printf("--------JNI_OnLoad-----");
return 65540;
}
puts("register native method failed!");
}
else
{
printf("cannot get class:%s\n", "demo2/jni/com/myapplication/myJNI");
}
}
return -1;
}

说明注册函数表在off_C860CE44中,双击进去

.data.rel.ro.local:C860CE44                               ; ===========================================================================
.data.rel.ro.local:C860CE44
.data.rel.ro.local:C860CE44 ; Segment type: Pure data
.data.rel.ro.local:C860CE44 AREA .data.rel.ro.local, DATA
.data.rel.ro.local:C860CE44 ; ORG 0xC860CE44
.data.rel.ro.local:C860CE44 0D B6 60 C8 off_C860CE44 DCD aCheckport ; DATA XREF: JNI_OnLoad+50↑o
.data.rel.ro.local:C860CE44 ; JNI_OnLoad+54↑o
.data.rel.ro.local:C860CE44 ; .text:off_C860A4FC↑o
.data.rel.ro.local:C860CE44 ; "checkport"
.data.rel.ro.local:C860CE48 17 B6 60 C8 DCD aLjavaLangStrin ; "()Ljava/lang/String;"
.data.rel.ro.local:C860CE4C 75 A1 60 C8 DCD sub_C860A174+1
.data.rel.ro.local:C860CE4C ; .data.rel.ro.local ends

果然代码在.data.rel.ro.local段中,这里描述的是java方法名,java方法签名,和对应的native方法,双击 sub_C860A174 进入

FILE *__fastcall sub_C860A174(JNIEnv *env)
{
FILE *result; // r0
FILE *v3; // r5
char v4[4104]; // [sp+4h] [bp+0h] BYREF _android_log_print(4, "JNI_LOG", byte_C860B494);
memset(v4, 0, 0x1000u);
result = popen("cat /proc/net/tcp |grep :5D8A", "r");
v3 = result;
if ( result )
{
if ( fgets(v4, 4096, result) )
exit(0);
pclose(v3);
return (FILE *)(*env)->NewStringUTF(env, "恭喜你,挑战成功!");
}
return result;
}

从这里可以看到,这个方法里在检查监听端口23946(十六进制5D8A),打开汇编代码,把这里nop掉

(Edit -> Patch program -> Change byte)

.text:C860A174                               CODE16
.text:C860A174
.text:C860A174 ; =============== S U B R O U T I N E =======================================
.text:C860A174
.text:C860A174 ; Attributes: bp-based frame fpd=0x1008
.text:C860A174
.text:C860A174 ; FILE *__fastcall sub_C860A174(JNIEnv *env)
.text:C860A174 sub_C860A174 ; DATA XREF: .data.rel.ro.local:C860CE4C↓o
.text:C860A174
.text:C860A174 var_C= -0xC
.text:C860A174
.text:C860A174 ; __unwind { // dword_C8609000
.text:C860A174 F0 B5 PUSH {R4-R7,LR}
.text:C860A176 AD F5 80 5D SUB.W SP, SP, #0x1000
.text:C860A17A 21 4C LDR R4, =(__stack_chk_guard_ptr - 0xC860A188)
.text:C860A17C 83 B0 SUB SP, SP, #0xC
.text:C860A17E 0D F5 80 52 ADD.W R2, SP, #0x100C+var_C
.text:C860A182 20 49 LDR R1, =(aJniLog - 0xC860A190) ; "JNI_LOG"
......
.text:C860A1CA FF F7 16 EF BLX exit ; 把这里nop掉
.text:C860A1CA
.text:C860A1CE ; ---------------------------------------------------------------------------
...... .text:C860A1F6
.text:C860A1F6 loc_C860A1F6 ; CODE XREF: sub_C860A174+7C↑j
.text:C860A1F6 0D F5 80 5D ADD.W SP, SP, #0x1000
.text:C860A1FA 03 B0 ADD SP, SP, #0xC
.text:C860A1FC F0 BD POP {R4-R7,PC}
.text:C860A1FC
.text:C860A1FC ; End of function sub_C860A174
3. JNI_OnLoad里还有一个可以的方法 SearchObjProcess(); 点进去看看
FILE *SearchObjProcess()
{
FILE *result; // r0
FILE *v1; // r5
int v2; // r11
int v3; // r10
int v4; // r9
unsigned __int8 v5; // r0
char *v6; // [sp+4h] [bp-103Ch]
int v7; // [sp+8h] [bp-1038h]
char v8[4140]; // [sp+14h] [bp-102Ch] BYREF memset(v8, 0, 0x1000u);
result = popen("ps", "r");
v1 = result;
if ( result )
{
while ( fgets(v8, 4096, v1) )
{
_android_log_print(4, "JNI_LOG", byte_C860B544, v8);
v6 = strstr(v8, "android_server");
v7 = (unsigned __int8)strstr(v8, "gdbserver");
v2 = (unsigned __int8)strstr(v8, "gdb");
v3 = (unsigned __int8)strstr(v8, "fuwu");
v4 = (unsigned __int8)strstr(v8, "android_ser");
v5 = (unsigned __int8)strstr(v8, "and_");
if ( v6 || v7 || v2 || v3 || v4 || v5 )
exit(0);
}
return (FILE *)pclose(v1);
}
return result;
}

这里可以看到就是在对进程名关键字进行检查,同上直接把exit给nop掉

4. ctrl+s 看看段列表情况,发现有一个.init_array段,有这个段说明里面有东西,进去看看,有可能有反调试的代码
.init_array:C860CE58                               ; ELF Initialization Function Table
.init_array:C860CE58 ; ===========================================================================
.init_array:C860CE58
.init_array:C860CE58 ; Segment type: Pure data
.init_array:C860CE58 AREA .init_array, DATA
.init_array:C860CE58 ; ORG 0xC860CE58
.init_array:C860CE58 ED A0 60 C8 DCD thread_create+1
.init_array:C860CE5C 00 00 00 00 ALIGN 0x10
.init_array:C860CE5C ; .init_array ends
.init_array:C860CE5C

里面有个thread_create函数,看来是有情况,跟进去看看

.text:C860A0EC                               ; int thread_create()
.text:C860A0EC EXPORT thread_create
.text:C860A0EC thread_create ; DATA XREF: .init_array:C860CE58↓o
.text:C860A0EC ; __unwind { // dword_C8609000
.text:C860A0EC 10 B5 PUSH {R4,LR}
.text:C860A0EE 04 20 MOVS R0, #4 ; prio
.text:C860A0F0 0E 4C LDR R4, =(aJniLog - 0xC860A0F8) ; "JNI_LOG"
.text:C860A0F2 0F 4A LDR R2, =(aEnterThreadCre - 0xC860A0FA) ; "enter thread_create"
.text:C860A0F4 7C 44 ADD R4, PC ; "JNI_LOG"
.text:C860A0F6 7A 44 ADD R2, PC ; "enter thread_create"
.text:C860A0F8 21 46 MOV R1, R4 ; tag
.text:C860A0FA FF F7 66 EF BLX __android_log_print
.text:C860A0FA
.text:C860A0FE 0D 48 LDR R0, =(t0_ptr - 0xC860A108)
.text:C860A100 0D 4A LDR R2, =(thread_function_ptr - 0xC860A10E)
.text:C860A102 00 21 MOVS R1, #0 ; attr
.text:C860A104 78 44 ADD R0, PC ; t0_ptr
.text:C860A106 00 68 LDR R0, [R0] ; t0 ; newthread
.text:C860A108 0B 46 MOV R3, R1 ; arg
.text:C860A10A 7A 44 ADD R2, PC ; thread_function_ptr
.text:C860A10C 12 68 LDR R2, [R2] ; thread_function ; start_routine
.text:C860A10E FF F7 86 EF BLX pthread_create
.text:C860A10E
.text:C860A112 01 30 ADDS R0, #1
.text:C860A114 08 D1 BNE locret_C860A128
.text:C860A114
.text:C860A116 09 4A LDR R2, =(aFailToCreatePt - 0xC860A120) ; "fail to create pthread t0"
.text:C860A118 04 20 MOVS R0, #4 ; prio
.text:C860A11A 21 46 MOV R1, R4 ; tag
.text:C860A11C 7A 44 ADD R2, PC ; "fail to create pthread t0"
.text:C860A11E FF F7 54 EF BLX __android_log_print
.text:C860A11E
.text:C860A122 01 20 MOVS R0, #1 ; int
.text:C860A124 FF F7 68 EF BLX exit
.text:C860A124
.text:C860A128 ; ---------------------------------------------------------------------------
.text:C860A128
.text:C860A128 locret_C860A128 ; CODE XREF: thread_create+28↑j
.text:C860A128 10 BD POP {R4,PC}
.text:C860A128
.text:C860A128 ; End of function thread_create
.text:C860A128
.text:C860A128 ; ---------------------------------------------------------------------------
.text:C860A12A 00 BF ALIGN 4
.text:C860A12C 94 13 00 00 off_C860A12C DCD aJniLog - 0xC860A0F8 ; DATA XREF: thread_create+4↑r
.text:C860A12C ; "JNI_LOG"
.text:C860A130 E8 13 00 00 off_C860A130 DCD aEnterThreadCre - 0xC860A0FA
.text:C860A130 ; DATA XREF: thread_create+6↑r
.text:C860A130 ; "enter thread_create"
.text:C860A134 64 2E 00 00 off_C860A134 DCD t0_ptr - 0xC860A108 ; DATA XREF: thread_create+12↑r
.text:C860A138 62 2E 00 00 off_C860A138 DCD thread_function_ptr - 0xC860A10E
.text:C860A138 ; DATA XREF: thread_create+14↑r
.text:C860A13C D6 13 00 00 off_C860A13C DCD aFailToCreatePt - 0xC860A120
.text:C860A13C ; DATA XREF: thread_create+2A↑r
.text:C860A13C ; } // starts at C860A0EC ; "fail to create pthread t0"
.text:C860A140 CODE32
.text:C860A140
.text:C860A140 ; =============== S U B R O U T I N E =======================================
.text:C860A140

开启了一个线程去调用 thread_function_ptr ,该函数反编译分析

FILE *thread_function()
{
__pid_t v0; // r5
FILE *result; // r0
FILE *v2; // r4
int v3; // r5
char v4[20]; // [sp+0h] [bp-140h] BYREF
char v5[256]; // [sp+14h] [bp-12Ch] BYREF _android_log_print(4, "JNI_LOG", "enter thread_function");
v0 = getpid();
memset(v4, 0, sizeof(v4));
sprintf(v4, "/proc/%d/status", v0);
while ( 1 )
{
result = fopen(v4, "r");
v2 = result;
if ( !result )
return result;
v3 = 6;
while ( !feof(v2) )
{
fgets(v5, 255, v2);
_android_log_print(4, "JNI_LOG", "linestr:%s", v5);
if ( !--v3 )
{
if ( getnumberfor_str((int)v5) > 0 )
exit(0);
break;
}
}
fclose(v2);
sleep(1u);
}
}

这里就是在检查/proc/目标进程id/status 第六行的值,例子

tiffany:/ # cat /proc/4398/status
Name: m.myapplication
State: S (sleeping)
Tgid: 4398
Pid: 4398
PPid: 640
TracerPid: 0 //就是这里,如果被attach,这里会是其他进程的id,不会是0
Uid: 10151 10151 10151 10151
Gid: 10151 10151 10151 10151
Ngid: 0
FDSize: 128
......

直接把这里的exit也nop掉,,注意是改thread_function 的,而不是外部调用函数的,

6. IDA->Edit -> Patch program -> apply patch into file

ps: 这次我用androidkiller重打包成功,但是运行提示某个资源找不到,选择手动打ok了,运行成功

看来还是得多会几种方式

java -jar ../apktool_2.2.4.jar b anti-debug -o anti-debug-new.apk
java -jar ../signapk.jar ../testkey.x509.pem ../testkey.pk8 anti-debug-new.apk anti-debug-signed.apk

7. 重打包+签名+安装,发现APP可以正常动态调试了,反调试成功绕过

【Android逆向】反调试绕过的更多相关文章

  1. 编译Android内核 For nexus 5 以及绕过Android的反调试

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/54880488 前面的博客中已经记录了Nexus 5手机的Android 4.4.4 ...

  2. 《Android逆向反编译代码注入》 - 逆向安全入门必看视频教程

      适合人群: Android开发人员.逆向反编译开发人员.以及对Android逆向安全感兴趣的朋友. 视频地址: 51CTO学院:https://edu.51cto.com/course/24485 ...

  3. 解决Android加固多进程ptrace反调试的思路整理

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/53613481 一.Android多进程反调试的原理代码 当ptrace附加目标进程 ...

  4. 修改Android手机内核,绕过反调试

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/57086486 0x1.手机设备环境 Model number: Nexus 5 O ...

  5. 手动绕过百度加固Debug.isDebuggerConnected反调试的方法

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78237571 1.调用Debug.isDebuggerConnected函数这种反 ...

  6. [转]Android逆向之动态调试总结

    一.在SO中关键函数上下断点 刚学逆向调试时.大多都满足于在SO中某关键函数上下断点.然后通过操作应用程序,去触发这个断点,然后进行调试 详细的步骤可以参见非虫大大的<Android软件安全与逆 ...

  7. 一种绕过PTRACE反调试的办法

    Linux 系统gdb等调试器,都是通过ptrace系统调用实现.Android加固中,ptrace自身防止调试器附加是一种常用的反调试手段. 调试时一般需要手工在ptrace处下断点,通过修改ptr ...

  8. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)

    Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...

  9. 浅谈android反调试之 转发端口

    反调试方案: 我们最通常使用的动态工具是IDA, IDA的动态调试端口默认为23946,我们可以通过/pro/net/tcp 查看android 系统所有TCP Socket 启动android_se ...

  10. 浅谈android反调试之轮询TracePid(解决方案是特色)

    参考文章: 1.  http://bbs.pediy.com/thread-207538.htm 2.  http://www.wjdiankong.cn/android 需求: 常见的Android ...

随机推荐

  1. [转帖]为什么不推荐使用/etc/fstab

    https://www.jianshu.com/p/af49a5d0553f 对于工作中使用服务器的公司来讲,每到节假日来临时,总免不了对服务器进行下电.而收假回来的早上,则会有一个早上的时间会花费在 ...

  2. [转帖]kafka_export 部署实战

    https://zhuanlan.zhihu.com/p/57704357 Kafka Exporter 监控 Kafka 实时数据 需要安装的组件 Prometheus:时序数据库,按时间保存监控历 ...

  3. [转帖]redis 持久化方式 - aof 和 rdb 区别

    https://wenfh2020.com/2020/04/01/redis-persistence-diff/   aof 和 rdb 是 redis 持久化的两种方式.我们看看它们的特点和具体应用 ...

  4. [转帖]金仓数据库KingbaseES V8R6 中unlogged表

    KingbaseESV8R6有一种表称为unlogged,在该表新建的索引也属于unlogged.和普通表的区别是,对该表进行DML操作时候不将该表的变更记录变更写入到wal文件中.在数据库异常关机或 ...

  5. [转帖]修改vcenter数据库账号密码

    1.修改sqlserver sa账号密码 2.停止vcenter服务 cd C:\Program Files\VMware\vCenter Server\bin service-control --l ...

  6. Redis lua脚本简要学习

    Redis lua脚本简要学习 背景 上周督促客户从Windows平台升级到了Linux平台. redis一周相安无事. 但是这周一突然又出现了卡断和慢的情况. 只能继续进行分析. 分析思路 现场日志 ...

  7. 【实践篇】最全的【DDD领域建模】小白学习手册(文末附资料)

    导读 DDD领域建模被各个大小厂商提起并应用,而每个人都有自己的理解,本文就是针对小白,系统地讲解DDD到底是什么,解决了什么问题,及一些建议和实践.本文主要是思想的一种碰撞和分享,希望能对朋友们有所 ...

  8. 小白学k8s(2)理解flannel网络

    理解flannel网络 简介 Kubernetes中的网络 flannel 总结 参考 理解flannel网络 简介 Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简 ...

  9. PaddleHub实战篇{词法分析模型LAC、情感分类ERNIE Tiny}训练、部署【三】

     相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨: ...

  10. centos7.9重启网卡提示Failed to start LSB: Bring up/down networking.

    前几天给一台机器状态centos7.9系统,设备有2个网口,今天重启网卡一直失败, 查看network状态,怀疑是eth0网卡有问题 查看eth0的网卡配置,发现是eth0网卡的BOOTPROTO=d ...