0x00 简单介绍

  目前我己知的APK加固主要有以下两种方式(或有其它的方式有待发现)

隐藏dex文件:通过对目标DEX文件进行整体加密或压缩方式把整个dex转换为另外一个文件存放在assets文件夹中或者其它地方,然后利用类加载器技术进行内存解密并加载运行。

修改dex结构:抽取DexCode中的字节码指令后用零去填充,或者修改方法属性等操作,运行时在内存中做修正、修复等处理工作。

0x01 APK加固前后对比

  整体来看一下原始APK包和加固后的APK包结构相关变化

图1

图1所示加固后的APK包变化如下:

新增2个文件夹:

assets文件夹中增加3个文件

data

dx

pk

lib文件夹中增加了2个so文件

libedog.so

libfdog.so

被修改的文件:

AndroidManifest.xml

classes.dex

0x02 壳流程分析

我们用AndroidKiller反编译加固后的APK, 反编译出错,错误日志如下:

图2

从图2可以看出反编译时出现了很多错误,我们用IDA对DEX进行反编译查看代码,发现方法指令都被零填充了,反编译后代码显示为nop样式,如图3所示。

图3

我们再来看看APK中的AndroidManifest.xml文件被修改了什么地方?

图4

从图4看到AndroidManifest.xml中的application新增了如下项做为壳的入口

android:name="com.edog.AppWrapper"该类为壳的入口,继续分析AppWrapper都做了些什么?

图5

图6

图7

从图5-7可以看出最终会调用到libedog.so中的dl函数,下面就开始动态调试分析该so的功能流程(如何动态调试就不说了,网上己经有很多的教程了)。

通过动态分析libedog.so中的dl函数主要功能是: 获得系统版本号->验证加固前后的签名是否一致->反调试->将抽走的指令映射到内存中还原指令时用到->HOOK函数dvmResolveClass->结束

代码流程如下:

 libedog.so:5D692C18             Java_com_edog_ELibrary_d1
libedog.so:5D692C18
libedog.so:5D692C18 var_F0= -0xF0
libedog.so:5D692C18 var_EC= -0xEC
libedog.so:5D692C18 var_E4= -0xE4
libedog.so:5D692C18 var_1C= -0x1C
libedog.so:5D692C18 arg_0=
libedog.so:5D692C18
libedog.so:5D692C18 F0 B5 PUSH {R4-R7,LR}
libedog.so:5D692C1A 4F LDR R7, =(dword_5D6A5E60 - 0x5D692C24)
libedog.so:5D692C1C B7 B0 SUB SP, SP, #0xDC
libedog.so:5D692C1E STR R3, [SP,#0xF0+var_F0]
libedog.so:5D692C20 7F ADD R7, PC ; dword_5D6A5E60
libedog.so:5D692C22 3F LDR R7, [R7]
libedog.so:5D692C24 3C LDR R1, [SP,#0xF0+arg_0]
libedog.so:5D692C26 1C MOVS R4, R0
libedog.so:5D692C28 3B LDR R3, [R7]
libedog.so:5D692C2A STR R1, [SP,#0xF0+var_EC]
libedog.so:5D692C2C A9 MOVS R1, #0xA9
libedog.so:5D692C2E STR R3, [SP,#0xF0+var_1C]
libedog.so:5D692C30 LDR R3, [R0]
libedog.so:5D692C32 LSLS R1, R1, #
libedog.so:5D692C34 4D LDR R5, =(aFjFj0fjFjFj4fj - 0x5D692C42)
libedog.so:5D692C36 5B LDR R3, [R3,R1]
libedog.so:5D692C38 1C MOVS R1, R2
libedog.so:5D692C3A MOVS R2, #
libedog.so:5D692C3C BLX R3
libedog.so:5D692C3E 7D ADD R5, PC ; "$fj] fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C40 2D LDR R5, [R5] ; "$fj] fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C42 4E LDR R6, =(aFjFj0fjFjFj4fj+ - 0x5D692C50)
libedog.so:5D692C44 STR R0, [R5]
libedog.so:5D692C46 1C MOVS R0, R4
libedog.so:5D692C48 F0 5C F8 BL _Z17ANDROID_API_LEVELP7_JNIEnv
libedog.so:5D692C4C 7E ADD R6, PC ; " fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C4E LDR R6, [R6] ; " fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C50 STR R0, [R6]
libedog.so:5D692C52 1C MOVS R0, R4
libedog.so:5D692C54 F0 F8 BL _Z24ANDROID_PLATFORM_VERSIONP7_JNIEnv
libedog.so:5D692C58 1C MOVS R0, R4
libedog.so:5D692C5A F0 A9 F8 BL _Z22ANDROID_PLATFORM_MODELP7_JNIEnv
libedog.so:5D692C5E 1C MOVS R0, R4
libedog.so:5D692C60 F0 D0 F8 BL _Z22ANDROID_PLATFORM_BRANDP7_JNIEnv
libedog.so:5D692C64 1C MOVS R0, R4
libedog.so:5D692C66 LDR R1, [SP,#0xF0+var_EC]
libedog.so:5D692C68 F0 8A FC BL _Z6verifyP7_JNIEnvP8_jobject ; 比较加固前后的签名是否一致
libedog.so:5D692C6C LDR R1, =(aDataDataSLibLi - 0x5D692C76)
libedog.so:5D692C6E 2A LDR R2, [R5]
libedog.so:5D692C70 A8 ADD R0, SP, #0xF0+var_E4
libedog.so:5D692C72 ADD R1, PC ; "/data/data/%s/lib/libfdog.so"
libedog.so:5D692C74 FF F7 B0 EE BLX sprintf
libedog.so:5D692C78 A8 ADD R0, SP, #0xF0+var_E4
libedog.so:5D692C7A 1C MOVS R1, R0
libedog.so:5D692C7C F0 FD BL _Z4antiPKcS0_ ; 反调试
libedog.so:5D692C80 F0 3E F9 BL _Z10openMemoryv ; 将抽走的指令映射到内存中来
libedog.so:5D692C80 ; assets中的data文件
libedog.so:5D692C84 LDR R3, [R4]
libedog.so:5D692C86 A9 MOVS R2, #0x2A4
libedog.so:5D692C8A 9B LDR R3, [R3,R2]
libedog.so:5D692C8C LDR R1, [SP,#0xF0+var_F0]
libedog.so:5D692C8E 1C MOVS R0, R4
libedog.so:5D692C90 MOVS R2, #
libedog.so:5D692C92 BLX R3
libedog.so:5D692C94 0D LDR R1, =(unk_5D6A2A0D - 0x5D692C9A)
libedog.so:5D692C96 ADD R1, PC
libedog.so:5D692C98 FF F7 A4 EE BLX strstr
libedog.so:5D692C9C CMP R0, #
libedog.so:5D692C9E D1 BNE loc_5D692CA6
libedog.so:5D692CA0 LDR R3, [R6]
libedog.so:5D692CA2 2B CMP R3, #0x14 ; 判断版本
libedog.so:5D692CA4 DD BLE loc_5D692CA8 ; 根据操作系统的版本
libedog.so:5D692CA4 ; hook对应的dvmResolveClass函数
libedog.so:5D692CA6
libedog.so:5D692CA6 loc_5D692CA6 ; CODE XREF: Java_com_edog_ELibrary_d1+86j
libedog.so:5D692CA6 MOVS R0, #
libedog.so:5D692CA8
libedog.so:5D692CA8 loc_5D692CA8 ; CODE XREF: Java_com_edog_ELibrary_d1+8Cj
libedog.so:5D692CA8 F0 E8 FB BL _Z7restorei ; 根据操作系统的版本
libedog.so:5D692CA8 ; hook对应的dvmResolveClass函数
libedog.so:5D692CAC 9A LDR R2, [SP,#0xF0+var_1C]
libedog.so:5D692CAE 3B LDR R3, [R7]
libedog.so:5D692CB0 9A CMP R2, R3
libedog.so:5D692CB2 D0 BEQ loc_5D692CB8
libedog.so:5D692CB4 FF F7 9C EE BLX sub_5D6929F0
libedog.so:5D692CB8 ; ---------------------------------------------------------------------------
libedog.so:5D692CB8
libedog.so:5D692CB8 loc_5D692CB8 ; CODE XREF: Java_com_edog_ELibrary_d1+9Aj
libedog.so:5D692CB8 B0 ADD SP, SP, #0xDC
libedog.so:5D692CBA F0 BD POP {R4-R7,PC}
libedog.so:5D692CBA ; End of function Java_com_edog_ELibrary_d1
libedog.so:5D692CBA
libedog.so:5D692CBA ; -------------------------------------

0x03 指令还原算法分析

原始指令还原时机就是在dvmResolveClass的hook函数中对对指令进行解密还原,以下结构的中的几个值会用到,因为被保护后的方法中的 debugInfoOff的值被修改成从0x20000000开始的一个值,该值在指令还原时起到重要作用。

 struct DexCode {
u2 registersSize;
u2 insSize;
u2 outsSize;
u2 triesSize;
u4 debugInfoOff; /* file offset to debug info stream */
u4 insnsSize; /* size of the insns array, in u2 units */
u2 insns[];
};

指令还原大致流程如下:

判断是否为保护的类->判断debuginfo值大于0x1FFFFFFF->将debuginfo值左移8位再右移6位->将移位后的值加上加密指令在内存中的开始址取4字节做为偏移->将偏移加上加密指令在内存中的开始地址定位到对应方法的指令->解密指令并还原->清零debuginfo值->结束。

解密指令算法流程如下:(每4字节进行xor)

XorArray函数中进行解密操作->将方法debuginfo值进行crc32计算得到一个值->crc32计算得到的值与指令每4字节进行xor->4字节结束后再将crc32值用PolyXorKey函数生成一个新的4字节数做为密钥,一直循环到解密完成。

代码流程如下

 libedog.so:5D693144
libedog.so:5D693144 _Z13restoreMethodP11ClassObjectP6Method ; CODE XREF: _Z10replaceFunP11ClassObjectjb+22p
libedog.so:5D693144 ; _Z10replaceFunP11ClassObjectjb+3Ap
libedog.so:5D693144
libedog.so:5D693144 var_34= -0x34
libedog.so:5D693144 Debug_info= -0x30
libedog.so:5D693144 var_2C= -0x2C
libedog.so:5D693144 codeSize= -0x28
libedog.so:5D693144 data= -0x24
libedog.so:5D693144 codeoffset= -0x1C
libedog.so:5D693144
libedog.so:5D693144 F0 B5 PUSH {R4-R7,LR}
libedog.so:5D693146 B0 SUB SP, SP, #0x24
libedog.so:5D693148 0F 1E SUBS R7, R1, #
libedog.so:5D69314A 5C D0 BEQ loc_5D693206
libedog.so:5D69314C LDR R4, [R0,#0x18]
libedog.so:5D69314E 2C CMP R4, #
libedog.so:5D693150 D0 BEQ loc_5D693206
libedog.so:5D693152 1C MOVS R0, R4
libedog.so:5D693154 4C MOVS R1, #'L'
libedog.so:5D693156 FF F7 A0 EC BLX strchr
libedog.so:5D69315A CMP R0, #
libedog.so:5D69315C D0 BEQ loc_5D693206
libedog.so:5D69315E 3E 6A LDR R6, [R7,#0x20]
libedog.so:5D693160 2E CMP R6, #
libedog.so:5D693162 D0 BEQ loc_5D693206
libedog.so:5D693164 1C MOVS R5, R6
libedog.so:5D693166 3D SUBS R5, #0x10
libedog.so:5D693168 AA LDR R2, [R5,#]
libedog.so:5D69316A STR R2, [SP,#0x38+Debug_info]
libedog.so:5D69316C EB LDRH R3, [R5,#]
libedog.so:5D69316E EA LDR R2, [R5,#0xC]
libedog.so:5D693170 STR R3, [SP,#0x38+var_2C]
libedog.so:5D693172 STR R2, [SP,#0x38+codeSize]
libedog.so:5D693174 4B LDR R3, =0x1FFFFFFF
libedog.so:5D693176 9A LDR R2, [SP,#0x38+Debug_info]
libedog.so:5D693178 9A CMP R2, R3 ; 判断debuginfo值大于 0x1FFFFFFF (因为被保护的方法debuginfo从0X20000000开始)
libedog.so:5D69317A D9 BLS loc_5D693206
libedog.so:5D69317C LDR R1, =(aLandroid - 0x5D693184)
libedog.so:5D69317E 1C MOVS R0, R4
libedog.so:5D693180 ADD R1, PC ; "Landroid/"
libedog.so:5D693182 FF F7 EC BLX strstr ; 是系统的类就跳过
libedog.so:5D693186 CMP R0, #
libedog.so:5D693188 3D D1 BNE loc_5D693206
libedog.so:5D69318A LDRB R6, [R6]
libedog.so:5D69318C STR R6, [SP,#0x38+var_34]
libedog.so:5D69318E 2E CMP R6, #
libedog.so:5D693190 D1 BNE loc_5D693206
libedog.so:5D693192 4B LDR R3, =(aFjFj0fjFjFj4fj+0xC - 0x5D69319C)
libedog.so:5D693194 A8 ADD R0, SP, #0x38+codeoffset
libedog.so:5D693196 STR R6, [SP,#0x38+codeoffset]
libedog.so:5D693198 7B ADD R3, PC ; "(fj],fj]4fj]i]"
libedog.so:5D69319A 1B LDR R3, [R3] ; "(fj],fj]4fj]i]"
libedog.so:5D69319C 1B LDR R3, [R3] ; data数据
libedog.so:5D69319E STR R3, [SP,#0x38+data]
libedog.so:5D6931A0 9B LDR R3, [SP,#0x38+Debug_info]
libedog.so:5D6931A2 9A LDR R2, [SP,#0x38+data]
libedog.so:5D6931A4 LSLS R1, R3, #
libedog.so:5D6931A6 LSRS R1, R1, #
libedog.so:5D6931A8 ADDS R1, R1, R2
libedog.so:5D6931AA MOVS R2, #
libedog.so:5D6931AC FF F7 EC BLX memcpy_0
libedog.so:5D6931B0 9A LDR R2, [SP,#0x38+var_2C]
libedog.so:5D6931B2 9C LDR R4, [SP,#0x38+codeSize]
libedog.so:5D6931B4 LSLS R3, R2, #
libedog.so:5D6931B6 ADDS R4, #
libedog.so:5D6931B8 E4 ADDS R4, R4, R3
libedog.so:5D6931BA 1C MOVS R3, R2
libedog.so:5D6931BC ADDS R3, #
libedog.so:5D6931BE 9B LSLS R3, R3, #
libedog.so:5D6931C0 E4 ADDS R4, R4, R3
libedog.so:5D6931C2 LSLS R4, R4, #
libedog.so:5D6931C4 1C MOVS R0, R4
libedog.so:5D6931C6 FF F7 EC BLX malloc
libedog.so:5D6931CA 1C MOVS R2, R4
libedog.so:5D6931CC 1C MOVS R6, R0
libedog.so:5D6931CE LDR R1, [SP,#0x38+var_34]
libedog.so:5D6931D0 FF F7 5C EC BLX memset_0
libedog.so:5D6931D4 1C MOVS R1, R5
libedog.so:5D6931D6 1C MOVS R2, R4
libedog.so:5D6931D8 1C MOVS R0, R6
libedog.so:5D6931DA FF F7 EC BLX memcpy_0
libedog.so:5D6931DE 9B LDR R3, [SP,#0x38+codeSize]
libedog.so:5D6931E0 9A LDR R2, [SP,#0x38+data]
libedog.so:5D6931E2 LDR R1, [SP,#0x38+codeoffset]
libedog.so:5D6931E4 5D LSLS R5, R3, #
libedog.so:5D6931E6 LDR R0, [SP,#0x38+Debug_info]
libedog.so:5D6931E8 ADDS R1, R2, R1
libedog.so:5D6931EA MOVS R3, #
libedog.so:5D6931EC 2A 1C MOVS R2, R5
libedog.so:5D6931EE F0 1E EF BLX dbone_crypt_ins ; 解密指令
libedog.so:5D6931F2 9B LDR R3, [SP,#0x38+var_34]
libedog.so:5D6931F4 1C MOVS R4, R6
libedog.so:5D6931F6 ADDS R4, #0x10
libedog.so:5D6931F8 1C MOVS R1, R0
libedog.so:5D6931FA B3 STR R3, [R6,#] ; 清空Debug_info
libedog.so:5D6931FC 1C MOVS R0, R4
libedog.so:5D6931FE 2A 1C MOVS R2, R5
libedog.so:5D693200 FF F7 3E EC BLX memcpy_0 ; 还原指令
libedog.so:5D693204 3C STR R4, [R7,#0x20]
libedog.so:5D693206
libedog.so:5D693206 loc_5D693206 ; CODE XREF: _Z13restoreMethodP11ClassObjectP6Method+6j
libedog.so:5D693206 ; _Z13restoreMethodP11ClassObjectP6Method+Cj ...
libedog.so:5D693206 B0 ADD SP, SP, #0x24
libedog.so:5D693208 F0 BD POP {R4-R7,PC}
libedog.so:5D693208 ; End of function _Z13restoreMethodP1
解密指令
libedog.so:5D69502C
libedog.so:5D69502C dbone_crypt_ins ; CODE XREF: _Z13restoreMethodP11ClassObjectP6Method+AAp
libedog.so:5D69502C
libedog.so:5D69502C DecMode= -0x1C
libedog.so:5D69502C codeSize= -0x18
libedog.so:5D69502C codedata= -0x14
libedog.so:5D69502C key= -0x10
libedog.so:5D69502C crckey= -
libedog.so:5D69502C
libedog.so:5D69502C 2D E9 STMFD SP!, {R11,LR}
libedog.so:5D695030 B0 8D E2 ADD R11, SP, #
libedog.so:5D695034 D0 4D E2 SUB SP, SP, #0x18
libedog.so:5D695038 0B E5 STR R0, [R11,#key]
libedog.so:5D69503C 0B E5 STR R1, [R11,#codedata]
libedog.so:5D695040 0B E5 STR R2, [R11,#codeSize]
libedog.so:5D695044 1C 0B E5 STR R3, [R11,#DecMode] ;
libedog.so:5D695048 4B E2 SUB R3, R11, #-key
libedog.so:5D69504C A0 E1 MOV R0, R3
libedog.so:5D695050 A0 E3 MOV R1, #
libedog.so:5D695054 EB BL _Z5crc32Phj
libedog.so:5D695058 A0 E1 MOV R3, R0
libedog.so:5D69505C 0B E5 STR R3, [R11,#crckey]
libedog.so:5D695060 1C 1B E5 LDR R3, [R11,#DecMode]
libedog.so:5D695064 E3 CMP R3, #
libedog.so:5D695068 1A BNE loc_5D695088
libedog.so:5D69506C 1B E5 LDR R2, [R11,#crckey]
libedog.so:5D695070 1B E5 LDR R3, [R11,#codeSize]
libedog.so:5D695074 A0 E1 MOV R0, R2
libedog.so:5D695078 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D69507C 1B E5 LDR R2, [R11,#codedata]
libedog.so:5D695080 EB BL _Z8XorArrayjPhS_j
libedog.so:5D695084 0D EA B loc_5D6950C0
libedog.so:5D695088 ; ---------------------------------------------------------------------------
libedog.so:5D695088
libedog.so:5D695088 loc_5D695088 ; CODE XREF: dbone_crypt_ins+3Cj
libedog.so:5D695088 1C 1B E5 LDR R3, [R11,#DecMode]
libedog.so:5D69508C E3 CMP R3, #
libedog.so:5D695090 1A BNE loc_5D6950B0
libedog.so:5D695094 1B E5 LDR R2, [R11,#key]
libedog.so:5D695098 1B E5 LDR R3, [R11,#codeSize]
libedog.so:5D69509C A0 E1 MOV R0, R2
libedog.so:5D6950A0 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D6950A4 1B E5 LDR R2, [R11,#codedata]
libedog.so:5D6950A8 B1 EB BL _Z13XorArray_0x99jPhS_j
libedog.so:5D6950AC EA B loc_5D6950C0
libedog.so:5D6950B0 ; ---------------------------------------------------------------------------
libedog.so:5D6950B0
libedog.so:5D6950B0 loc_5D6950B0 ; CODE XREF: dbone_crypt_ins+64j
libedog.so:5D6950B0 9F E5 LDR R3, =(aUsageDbone_cry - 0x5D6950BC)
libedog.so:5D6950B4 8F E0 ADD R3, PC, R3 ; "USAGE:dbone_crypt_ins(key,ins,ins_lenth"...
libedog.so:5D6950B8 A0 E1 MOV R0, R3
libedog.so:5D6950BC F6 FF EB BL puts
libedog.so:5D6950C0
libedog.so:5D6950C0 loc_5D6950C0 ; CODE XREF: dbone_crypt_ins+58j
libedog.so:5D6950C0 ; dbone_crypt_ins+80j
libedog.so:5D6950C0 1B E5 LDR R3, [R11,#codedata]
libedog.so:5D6950C4 A0 E1 MOV R0, R3
libedog.so:5D6950C8 D0 4B E2 SUB SP, R11, #
libedog.so:5D6950CC BD E8 LDMFD SP!, {R11,PC}
libedog.so:5D6950CC ; End of function dbone_crypt_ins
libedog.so:5D6950CC
libedog.so:5D6950CC ; ------------- //循环解密 libedog.so:5D695288 _Z8XorArrayjPhS_j ; CODE XREF: dbone_crypt_file+180p
libedog.so:5D695288 ; dbone_crypt_ins+54p
libedog.so:5D695288
libedog.so:5D695288 codeSize= -0x24
libedog.so:5D695288 codedata1= -0x20
libedog.so:5D695288 codedata= -0x1C
libedog.so:5D695288 crckey= -0x18
libedog.so:5D695288 crckey1= -0x14
libedog.so:5D695288 crckeyaddr= -0x10
libedog.so:5D695288 crckeyindex= -0xC
libedog.so:5D695288 index= -
libedog.so:5D695288
libedog.so:5D695288 2D E9 STMFD SP!, {R11,LR}
libedog.so:5D69528C B0 8D E2 ADD R11, SP, #
libedog.so:5D695290 D0 4D E2 SUB SP, SP, #0x20
libedog.so:5D695294 0B E5 STR R0, [R11,#crckey]
libedog.so:5D695298 1C 0B E5 STR R1, [R11,#codedata]
libedog.so:5D69529C 0B E5 STR R2, [R11,#codedata1]
libedog.so:5D6952A0 0B E5 STR R3, [R11,#codeSize]
libedog.so:5D6952A4 1B E5 LDR R3, [R11,#crckey]
libedog.so:5D6952A8 0B E5 STR R3, [R11,#crckey1]
libedog.so:5D6952AC 4B E2 SUB R3, R11, #-crckey1
libedog.so:5D6952B0 0B E5 STR R3, [R11,#crckeyaddr]
libedog.so:5D6952B4 A0 E3 MOV R3, #
libedog.so:5D6952B8 0B E5 STR R3, [R11,#index]
libedog.so:5D6952BC A0 E3 MOV R3, #
libedog.so:5D6952C0 0C 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D6952C4 A0 E3 MOV R3, #
libedog.so:5D6952C8 0B E5 STR R3, [R11,#index]
libedog.so:5D6952CC 1E EA B loc_5D69534C
libedog.so:5D6952D0 ; ---------------------------------------------------------------------------
libedog.so:5D6952D0
libedog.so:5D6952D0 loc_5D6952D0 ; CODE XREF: _Z8XorArrayjPhS_j+E0j
libedog.so:5D6952D0 1B E5 LDR R3, [R11,#index]
libedog.so:5D6952D4 1B E5 LDR R2, [R11,#codedata1]
libedog.so:5D6952D8 E0 ADD R3, R2, R3
libedog.so:5D6952DC 1B E5 LDR R2, [R11,#index]
libedog.so:5D6952E0 1C 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D6952E4 E0 ADD R2, R1, R2
libedog.so:5D6952E8 D2 E5 LDRB R1, [R2]
libedog.so:5D6952EC 0C 1B E5 LDR R2, [R11,#crckeyindex]
libedog.so:5D6952F0 1B E5 LDR R0, [R11,#crckeyaddr]
libedog.so:5D6952F4 E0 ADD R2, R0, R2
libedog.so:5D6952F8 D2 E5 LDRB R2, [R2]
libedog.so:5D6952FC E0 EOR R2, R1, R2
libedog.so:5D695300 FF E2 AND R2, R2, #0xFF
libedog.so:5D695304 C3 E5 STRB R2, [R3]
libedog.so:5D695308 0C 1B E5 LDR R3, [R11,#crckeyindex]
libedog.so:5D69530C E3 CMP R3, # ; 比较key是否结束
libedog.so:5D695310 1A BNE loc_5D695334
libedog.so:5D695314 1B E5 LDR R3, [R11,#crckey1]
libedog.so:5D695318 A0 E1 MOV R0, R3
libedog.so:5D69531C 6C FF FF EB BL _Z10PolyXorKeyj
libedog.so:5D695320 A0 E1 MOV R3, R0
libedog.so:5D695324 0B E5 STR R3, [R11,#crckey1]
libedog.so:5D695328 A0 E3 MOV R3, #
libedog.so:5D69532C 0C 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D695330 EA B loc_5D695340
libedog.so:5D695334 ; ---------------------------------------------------------------------------
libedog.so:5D695334
libedog.so:5D695334 loc_5D695334 ; CODE XREF: _Z8XorArrayjPhS_j+88j
libedog.so:5D695334 0C 1B E5 LDR R3, [R11,#crckeyindex]
libedog.so:5D695338 E2 ADD R3, R3, #
libedog.so:5D69533C 0C 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D695340
libedog.so:5D695340 loc_5D695340 ; CODE XREF: _Z8XorArrayjPhS_j+A8j
libedog.so:5D695340 1B E5 LDR R3, [R11,#index]
libedog.so:5D695344 E2 ADD R3, R3, #
libedog.so:5D695348 0B E5 STR R3, [R11,#index]
libedog.so:5D69534C
libedog.so:5D69534C loc_5D69534C ; CODE XREF: _Z8XorArrayjPhS_j+44j
libedog.so:5D69534C 1B E5 LDR R2, [R11,#codeSize]
libedog.so:5D695350 1B E5 LDR R3, [R11,#index]
libedog.so:5D695354 E1 CMP R2, R3
libedog.so:5D695358 A0 D3 MOVLE R3, #
libedog.so:5D69535C A0 C3 MOVGT R3, #
libedog.so:5D695360 FF E2 AND R3, R3, #0xFF
libedog.so:5D695364 E3 CMP R3, #
libedog.so:5D695368 D8 FF FF 1A BNE loc_5D6952D0
libedog.so:5D69536C D0 4B E2 SUB SP, R11, #
libedog.so:5D695370 BD E8 LDMFD SP!, {R11,PC}
libedog.so:5D695370 ; End of function _Z8XorArrayjPhS_j
libedog.so:5D695370
libedog.so:5D695374
libedog.so:5D695374 ; =============== S U B R O U T

0x04 编写修复程序

修复程序主要分为解析dex与解密两个步骤来完成,这里只贴出部分代码详细的请看工程,代码写得比较粗操,看下思路就行了,有性趣的就慢慢撸吧!

 void fixdexClassData()
{ DexFile *dexFile = &gDexFile; char * Tag = "L";
char * ClassTag = "Landroid/"; const DexClassDef* classdef;
u4 count = dexFile->pHeader->classDefsSize; printf("该DEX共有%d 个类\n", count); const u1* pEncodedData = NULL;
DexClassData* pClassData = NULL;
const char *descriptor = NULL; int FileSize = file_size(); gCodeData = (u1*)malloc(FileSize);
if (NULL == gCodeData)
{
printf("分配内存失败!\n");
return;
}
memset(gCodeData, , FileSize); //获得加密指令数据
GetCodeData(gCodeData, FileSize); if (NULL == gCodeData)
{
printf("获取加密指令数据出错!\n");
return;
} for(u4 i=; i<count; i++){
classdef = dexGetClassDef(dexFile, i); descriptor = getTpyeIdString(dexFile, classdef->classIdx); if (strstr(descriptor,Tag) == NULL)
{
continue;
} //跳过一些系统的类
if (strstr(descriptor, ClassTag) != NULL)
{
continue;
} pEncodedData = dexFile->baseAddr + classdef->classDataOff;
pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); if (pClassData == NULL) {
continue;
} FixdexMethodInsns(dexFile, pClassData, descriptor); } } void FixdexMethodInsns(DexFile *dexFile, const DexClassData*classData ,const char* className)
{
int idx = ;
DexMethod *method = NULL;
const DexMethodId* methodId = NULL;
DexCode* code = NULL;
const char* methodName;
method = classData->directMethods;
methodId = dexFile->pMethodIds;
unsigned int CodeDataOffset = ;
u1 * tempCode = NULL;
for (int i = ; i < (int) classData->header.directMethodsSize; i++) {
idx = classData->directMethods[i].methodIdx; methodId = dexGetMethodId(dexFile, idx);
methodName = dexStringById(dexFile, methodId->nameIdx); DexCode* pCode = dexGetCode(dexFile, &classData->directMethods[i]);
if (NULL == pCode)
{
continue;
}
//判断是否为保护后的方法,如果是就修复指令
if ( (pCode->debugInfoOff > 0x1FFFFFFF) && (pCode->insns[] == 0X00))
{
//求加密指令的偏移
CodeDataOffset = pCode->debugInfoOff << 0x8;
CodeDataOffset >>= 0x6;
//解密指令
tempCode = DecCode(gCodeData+CodeDataOffset, pCode->insnsSize*sizeof(u2), pCode->debugInfoOff, gCodeData);
//修复指令
memcpy(pCode->insns, tempCode, (pCode->insnsSize)*sizeof(u2));
pCode->debugInfoOff = 0x00;
printf("修复%s 类中的%s 方法成功! 大小%X\n",className, methodName,pCode->insnsSize);
if (NULL != tempCode)
{
free(tempCode);
tempCode = NULL;
}
}
} for (int i = ; i < (int) classData->header.virtualMethodsSize; i++) {
idx = classData->virtualMethods[i].methodIdx; methodId = dexGetMethodId(dexFile, idx);
methodName = dexStringById(dexFile, methodId->nameIdx); DexCode* pCode = dexGetCode(dexFile, &classData->virtualMethods[i]);
if (NULL == pCode)
{
continue;
}
//判断是否为保护后的方法,如果是就修复指令
if ( (pCode->debugInfoOff > 0x1FFFFFFF) && (pCode->insns[] == 0X00))
{
//求加密指令的偏移
CodeDataOffset = pCode->debugInfoOff << 0x8;
CodeDataOffset >>= 0x6;
//解密指令
tempCode = DecCode(gCodeData+CodeDataOffset, pCode->insnsSize*sizeof(u2), pCode->debugInfoOff, gCodeData);
//修复指令
memcpy(pCode->insns, tempCode, (pCode->insnsSize)*sizeof(u2));
pCode->debugInfoOff = 0x00;
printf("修复%s 类中的%s 方法成功! 大小%X\n",className, methodName,pCode->insnsSize);
if (NULL != tempCode)
{
free(tempCode);
tempCode = NULL;
}
}
}
return;
}
unsigned int PolyXorKey(DWORD crckey)
{
unsigned int dwKey;
char temp;
unsigned __int8 temp1;
unsigned __int8 temp2;
char *pKey;
int temp3;
int j;
int i; j = ;
temp3 = ;
pKey = (char *)&dwKey;
temp2 = ;
temp1 = ;
temp = ;
dwKey = crckey ^ 0xDF138530;
i = ;
while ( i <= )
{
temp2 = *pKey;
j = ;
temp3 = ;
while ( j > )
{
temp = (temp2 & j / ) >> (temp3 - );
temp1 = ((signed int)(unsigned __int8)(temp2 & j) >> temp3) ^ temp;
temp1 <<= temp3;
temp2 |= temp1;
j /= ;
--temp3;
}
temp = temp2 & ;
temp1 = temp2 & ^ temp2 & ;
*pKey = temp2;
++i;
++pKey;
}
return dwKey;
}

0x05 测试与总结

将加固后的 APK中assets文件夹中的data文件与classes.dex放在修复程序同一个目录中,然后运行修复程序。

图8

去掉AndroidManifest.xml中的壳入口,将修复后的classes.dex重新打包反编译,成功运行,如图9所示能正常反编译源码,至此,分析完毕。

图9

壳流程总结:

AndroidManifest.xml中的壳入口->com.edog.AppWrapper->

so中Java_com_edog_ELibrary_d1->hook dvmResolveClass函数->在dvmResolveClass hook函数中修复指令->结束。

语言表达不行,说的很杂,自己都觉得文章没有任何逻辑可言,如果大家能从中获得一些思路那也是好的, 不过这次分析让自己学到了很多,感谢APK加固作者。

样本及pdf文档下载

http://yunpan.cn/cmApFwTesyPGk (提取码:b37f)

最新文章

  1. CSS 布局口诀
  2. js日期校验
  3. linux系统的初化始配置 IP 主机名 防火墙 selinux
  4. 将本地项目上传到Github
  5. Windows命令行下pip安装python whl包
  6. ES6箭头函数和它的作用域
  7. JaveScript运算符(JS知识点归纳三)
  8. Python系列之 - 反射
  9. SQL DISTINCT去掉重复的数据统计方法【转】
  10. Spring中IOC和AOP的详细解释(转)
  11. Quartz.Net进阶之三:SimpleTrigger详述
  12. C++11 AUTO 类型实践
  13. Java 基础【17】 异常与自定义异常
  14. GoldenGate 12.2抽取Oracle 12c多租户配置过程
  15. C# 依赖注入那些事儿
  16. SVN集成compare4比较软件
  17. CSAPP lab2 二进制拆弹 binary bombs phase_3
  18. Hyperledger 项目
  19. react-router的browserHistory/react-router-dom的BrowserRouter刷新页面404问题解决
  20. sqlalchemy多外键关联

热门文章

  1. Zookeeper基础使用
  2. centos下yum搭建安装linux+apache+mysql+php环境教程
  3. 黑马学习连接池 druid JdbcTemplate c3p0 池技术
  4. shell参数位置
  5. react 中文文档案例七 (温度计)
  6. codeforces-473D Mahmoud and Ehab and another array construction task (素数筛法+贪心)
  7. poj1964最大子矩阵 (单调栈加枚举)
  8. vue中this.$router.push() 传参
  9. Dev Express Report 学习总结(七)Dev Express Reports 常见知识点总结
  10. Python 15 I/O编程