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中的d1函数主要功能是: 获得系统版本号->验证加固前后的签名是否一致->反调试->将抽走的指令映射到内存中还原指令时用到->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= 0
libedog.so:5D692C18
libedog.so:5D692C18 F0 B5 PUSH {R4-R7,LR}
libedog.so:5D692C1A 28 4F LDR R7, =(dword_5D6A5E60 - 0x5D692C24)
libedog.so:5D692C1C B7 B0 SUB SP, SP, #0xDC
libedog.so:5D692C1E 00 93 STR R3, [SP,#0xF0+var_F0]
libedog.so:5D692C20 7F 44 ADD R7, PC ; dword_5D6A5E60
libedog.so:5D692C22 3F 68 LDR R7, [R7]
libedog.so:5D692C24 3C 99 LDR R1, [SP,#0xF0+arg_0]
libedog.so:5D692C26 04 1C MOVS R4, R0
libedog.so:5D692C28 3B 68 LDR R3, [R7]
libedog.so:5D692C2A 01 91 STR R1, [SP,#0xF0+var_EC]
libedog.so:5D692C2C A9 21 MOVS R1, #0xA9
libedog.so:5D692C2E 35 93 STR R3, [SP,#0xF0+var_1C]
libedog.so:5D692C30 03 68 LDR R3, [R0]
libedog.so:5D692C32 89 00 LSLS R1, R1, #2
libedog.so:5D692C34 22 4D LDR R5, =(aFjFj0fjFjFj4fj - 0x5D692C42)
libedog.so:5D692C36 5B 58 LDR R3, [R3,R1]
libedog.so:5D692C38 11 1C MOVS R1, R2
libedog.so:5D692C3A 00 22 MOVS R2, #0
libedog.so:5D692C3C 98 47 BLX R3
libedog.so:5D692C3E 7D 44 ADD R5, PC ; "$fj] fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C40 2D 68 LDR R5, [R5] ; "$fj] fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C42 20 4E LDR R6, =(aFjFj0fjFjFj4fj+4 - 0x5D692C50)
libedog.so:5D692C44 28 60 STR R0, [R5]
libedog.so:5D692C46 20 1C MOVS R0, R4
libedog.so:5D692C48 00 F0 5C F8 BL _Z17ANDROID_API_LEVELP7_JNIEnv
libedog.so:5D692C4C 7E 44 ADD R6, PC ; " fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C4E 36 68 LDR R6, [R6] ; " fj]0fj](fj],fj]4fj]i]"
libedog.so:5D692C50 30 60 STR R0, [R6]
libedog.so:5D692C52 20 1C MOVS R0, R4
libedog.so:5D692C54 00 F0 82 F8 BL _Z24ANDROID_PLATFORM_VERSIONP7_JNIEnv
libedog.so:5D692C58 20 1C MOVS R0, R4
libedog.so:5D692C5A 00 F0 A9 F8 BL _Z22ANDROID_PLATFORM_MODELP7_JNIEnv
libedog.so:5D692C5E 20 1C MOVS R0, R4
libedog.so:5D692C60 00 F0 D0 F8 BL _Z22ANDROID_PLATFORM_BRANDP7_JNIEnv
libedog.so:5D692C64 20 1C MOVS R0, R4
libedog.so:5D692C66 01 99 LDR R1, [SP,#0xF0+var_EC]
libedog.so:5D692C68 00 F0 8A FC BL _Z6verifyP7_JNIEnvP8_jobject ; 比较加固前后的签名是否一致
libedog.so:5D692C6C 16 49 LDR R1, =(aDataDataSLibLi - 0x5D692C76)
libedog.so:5D692C6E 2A 68 LDR R2, [R5]
libedog.so:5D692C70 03 A8 ADD R0, SP, #0xF0+var_E4
libedog.so:5D692C72 79 44 ADD R1, PC ; "/data/data/%s/lib/libfdog.so"
libedog.so:5D692C74 FF F7 B0 EE BLX sprintf
libedog.so:5D692C78 03 A8 ADD R0, SP, #0xF0+var_E4
libedog.so:5D692C7A 01 1C MOVS R1, R0
libedog.so:5D692C7C 00 F0 02 FD BL _Z4antiPKcS0_ ; 反调试
libedog.so:5D692C80 00 F0 3E F9 BL _Z10openMemoryv ; 将抽走的指令映射到内存中来
libedog.so:5D692C80 ; assets中的data文件
libedog.so:5D692C84 23 68 LDR R3, [R4]
libedog.so:5D692C86 A9 22 92 00 MOVS R2, #0x2A4
libedog.so:5D692C8A 9B 58 LDR R3, [R3,R2]
libedog.so:5D692C8C 00 99 LDR R1, [SP,#0xF0+var_F0]
libedog.so:5D692C8E 20 1C MOVS R0, R4
libedog.so:5D692C90 00 22 MOVS R2, #0
libedog.so:5D692C92 98 47 BLX R3
libedog.so:5D692C94 0D 49 LDR R1, =(unk_5D6A2A0D - 0x5D692C9A)
libedog.so:5D692C96 79 44 ADD R1, PC
libedog.so:5D692C98 FF F7 A4 EE BLX strstr
libedog.so:5D692C9C 00 28 CMP R0, #0
libedog.so:5D692C9E 02 D1 BNE loc_5D692CA6
libedog.so:5D692CA0 33 68 LDR R3, [R6]
libedog.so:5D692CA2 14 2B CMP R3, #0x14 ; 判断版本
libedog.so:5D692CA4 00 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 01 20 MOVS R0, #1
libedog.so:5D692CA8
libedog.so:5D692CA8 loc_5D692CA8 ; CODE XREF: Java_com_edog_ELibrary_d1+8Cj
libedog.so:5D692CA8 00 F0 E8 FB BL _Z7restorei ; 根据操作系统的版本
libedog.so:5D692CA8 ; hook对应的dvmResolveClass函数
libedog.so:5D692CAC 35 9A LDR R2, [SP,#0xF0+var_1C]
libedog.so:5D692CAE 3B 68 LDR R3, [R7]
libedog.so:5D692CB0 9A 42 CMP R2, R3
libedog.so:5D692CB2 01 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 37 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[1];
};
指令还原大致流程如下:
判断是否为保护的类->判断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 89 B0 SUB SP, SP, #0x24
libedog.so:5D693148 0F 1E SUBS R7, R1, #0
libedog.so:5D69314A 5C D0 BEQ loc_5D693206
libedog.so:5D69314C 84 69 LDR R4, [R0,#0x18]
libedog.so:5D69314E 00 2C CMP R4, #0
libedog.so:5D693150 59 D0 BEQ loc_5D693206
libedog.so:5D693152 20 1C MOVS R0, R4
libedog.so:5D693154 4C 21 MOVS R1, #'L'
libedog.so:5D693156 FF F7 A0 EC BLX strchr
libedog.so:5D69315A 00 28 CMP R0, #0
libedog.so:5D69315C 53 D0 BEQ loc_5D693206
libedog.so:5D69315E 3E 6A LDR R6, [R7,#0x20]
libedog.so:5D693160 00 2E CMP R6, #0
libedog.so:5D693162 50 D0 BEQ loc_5D693206
libedog.so:5D693164 35 1C MOVS R5, R6
libedog.so:5D693166 10 3D SUBS R5, #0x10
libedog.so:5D693168 AA 68 LDR R2, [R5,#8]
libedog.so:5D69316A 02 92 STR R2, [SP,#0x38+Debug_info]
libedog.so:5D69316C EB 88 LDRH R3, [R5,#6]
libedog.so:5D69316E EA 68 LDR R2, [R5,#0xC]
libedog.so:5D693170 03 93 STR R3, [SP,#0x38+var_2C]
libedog.so:5D693172 04 92 STR R2, [SP,#0x38+codeSize]
libedog.so:5D693174 25 4B LDR R3, =0x1FFFFFFF
libedog.so:5D693176 02 9A LDR R2, [SP,#0x38+Debug_info]
libedog.so:5D693178 9A 42 CMP R2, R3 ; 判断debuginfo值大于 0x1FFFFFFF (因为被保护的方法debuginfo从0X20000000开始)
libedog.so:5D69317A 44 D9 BLS loc_5D693206
libedog.so:5D69317C 24 49 LDR R1, =(aLandroid - 0x5D693184)
libedog.so:5D69317E 20 1C MOVS R0, R4
libedog.so:5D693180 79 44 ADD R1, PC ; "Landroid/"
libedog.so:5D693182 FF F7 30 EC BLX strstr ; 是系统的类就跳过
libedog.so:5D693186 00 28 CMP R0, #0
libedog.so:5D693188 3D D1 BNE loc_5D693206
libedog.so:5D69318A 36 78 LDRB R6, [R6]
libedog.so:5D69318C 01 96 STR R6, [SP,#0x38+var_34]
libedog.so:5D69318E 00 2E CMP R6, #0
libedog.so:5D693190 39 D1 BNE loc_5D693206
libedog.so:5D693192 20 4B LDR R3, =(aFjFj0fjFjFj4fj+0xC - 0x5D69319C)
libedog.so:5D693194 07 A8 ADD R0, SP, #0x38+codeoffset
libedog.so:5D693196 07 96 STR R6, [SP,#0x38+codeoffset]
libedog.so:5D693198 7B 44 ADD R3, PC ; "(fj],fj]4fj]i]"
libedog.so:5D69319A 1B 68 LDR R3, [R3] ; "(fj],fj]4fj]i]"
libedog.so:5D69319C 1B 68 LDR R3, [R3] ; data数据
libedog.so:5D69319E 05 93 STR R3, [SP,#0x38+data]
libedog.so:5D6931A0 02 9B LDR R3, [SP,#0x38+Debug_info]
libedog.so:5D6931A2 05 9A LDR R2, [SP,#0x38+data]
libedog.so:5D6931A4 19 02 LSLS R1, R3, #8
libedog.so:5D6931A6 89 09 LSRS R1, R1, #6
libedog.so:5D6931A8 89 18 ADDS R1, R1, R2
libedog.so:5D6931AA 04 22 MOVS R2, #4
libedog.so:5D6931AC FF F7 68 EC BLX memcpy_0
libedog.so:5D6931B0 03 9A LDR R2, [SP,#0x38+var_2C]
libedog.so:5D6931B2 04 9C LDR R4, [SP,#0x38+codeSize]
libedog.so:5D6931B4 93 00 LSLS R3, R2, #2
libedog.so:5D6931B6 08 34 ADDS R4, #8
libedog.so:5D6931B8 E4 18 ADDS R4, R4, R3
libedog.so:5D6931BA 13 1C MOVS R3, R2
libedog.so:5D6931BC 01 33 ADDS R3, #1
libedog.so:5D6931BE 9B 00 LSLS R3, R3, #2
libedog.so:5D6931C0 E4 18 ADDS R4, R4, R3
libedog.so:5D6931C2 64 00 LSLS R4, R4, #1
libedog.so:5D6931C4 20 1C MOVS R0, R4
libedog.so:5D6931C6 FF F7 26 EC BLX malloc
libedog.so:5D6931CA 22 1C MOVS R2, R4
libedog.so:5D6931CC 06 1C MOVS R6, R0
libedog.so:5D6931CE 01 99 LDR R1, [SP,#0x38+var_34]
libedog.so:5D6931D0 FF F7 5C EC BLX memset_0
libedog.so:5D6931D4 29 1C MOVS R1, R5
libedog.so:5D6931D6 22 1C MOVS R2, R4
libedog.so:5D6931D8 30 1C MOVS R0, R6
libedog.so:5D6931DA FF F7 52 EC BLX memcpy_0
libedog.so:5D6931DE 04 9B LDR R3, [SP,#0x38+codeSize]
libedog.so:5D6931E0 05 9A LDR R2, [SP,#0x38+data]
libedog.so:5D6931E2 07 99 LDR R1, [SP,#0x38+codeoffset]
libedog.so:5D6931E4 5D 00 LSLS R5, R3, #1
libedog.so:5D6931E6 02 98 LDR R0, [SP,#0x38+Debug_info]
libedog.so:5D6931E8 51 18 ADDS R1, R2, R1
libedog.so:5D6931EA 01 23 MOVS R3, #1
libedog.so:5D6931EC 2A 1C MOVS R2, R5
libedog.so:5D6931EE 01 F0 1E EF BLX dbone_crypt_ins ; 解密指令
libedog.so:5D6931F2 01 9B LDR R3, [SP,#0x38+var_34]
libedog.so:5D6931F4 34 1C MOVS R4, R6
libedog.so:5D6931F6 10 34 ADDS R4, #0x10
libedog.so:5D6931F8 01 1C MOVS R1, R0
libedog.so:5D6931FA B3 60 STR R3, [R6,#8] ; 清空Debug_info
libedog.so:5D6931FC 20 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 62 STR R4, [R7,#0x20]
libedog.so:5D693206
libedog.so:5D693206 loc_5D693206 ; CODE XREF: _Z13restoreMethodP11ClassObjectP6Method+6j
libedog.so:5D693206 ; _Z13restoreMethodP11ClassObjectP6Method+Cj ...
libedog.so:5D693206 09 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= -8
libedog.so:5D69502C
libedog.so:5D69502C 00 48 2D E9 STMFD SP!, {R11,LR}
libedog.so:5D695030 04 B0 8D E2 ADD R11, SP, #4
libedog.so:5D695034 18 D0 4D E2 SUB SP, SP, #0x18
libedog.so:5D695038 10 00 0B E5 STR R0, [R11,#key]
libedog.so:5D69503C 14 10 0B E5 STR R1, [R11,#codedata]
libedog.so:5D695040 18 20 0B E5 STR R2, [R11,#codeSize]
libedog.so:5D695044 1C 30 0B E5 STR R3, [R11,#DecMode] ; 1
libedog.so:5D695048 10 30 4B E2 SUB R3, R11, #-key
libedog.so:5D69504C 03 00 A0 E1 MOV R0, R3
libedog.so:5D695050 04 10 A0 E3 MOV R1, #4
libedog.so:5D695054 47 01 00 EB BL _Z5crc32Phj
libedog.so:5D695058 00 30 A0 E1 MOV R3, R0
libedog.so:5D69505C 08 30 0B E5 STR R3, [R11,#crckey]
libedog.so:5D695060 1C 30 1B E5 LDR R3, [R11,#DecMode]
libedog.so:5D695064 01 00 53 E3 CMP R3, #1
libedog.so:5D695068 06 00 00 1A BNE loc_5D695088
libedog.so:5D69506C 08 20 1B E5 LDR R2, [R11,#crckey]
libedog.so:5D695070 18 30 1B E5 LDR R3, [R11,#codeSize]
libedog.so:5D695074 02 00 A0 E1 MOV R0, R2
libedog.so:5D695078 14 10 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D69507C 14 20 1B E5 LDR R2, [R11,#codedata]
libedog.so:5D695080 80 00 00 EB BL _Z8XorArrayjPhS_j
libedog.so:5D695084 0D 00 00 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 30 1B E5 LDR R3, [R11,#DecMode]
libedog.so:5D69508C 00 00 53 E3 CMP R3, #0
libedog.so:5D695090 06 00 00 1A BNE loc_5D6950B0
libedog.so:5D695094 10 20 1B E5 LDR R2, [R11,#key]
libedog.so:5D695098 18 30 1B E5 LDR R3, [R11,#codeSize]
libedog.so:5D69509C 02 00 A0 E1 MOV R0, R2
libedog.so:5D6950A0 14 10 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D6950A4 14 20 1B E5 LDR R2, [R11,#codedata]
libedog.so:5D6950A8 B1 00 00 EB BL _Z13XorArray_0x99jPhS_j
libedog.so:5D6950AC 03 00 00 EA B loc_5D6950C0
libedog.so:5D6950B0 ; ---------------------------------------------------------------------------
libedog.so:5D6950B0
libedog.so:5D6950B0 loc_5D6950B0 ; CODE XREF: dbone_crypt_ins+64j
libedog.so:5D6950B0 18 30 9F E5 LDR R3, =(aUsageDbone_cry - 0x5D6950BC)
libedog.so:5D6950B4 03 30 8F E0 ADD R3, PC, R3 ; "USAGE:dbone_crypt_ins(key,ins,ins_lenth"...
libedog.so:5D6950B8 03 00 A0 E1 MOV R0, R3
libedog.so:5D6950BC 99 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 14 30 1B E5 LDR R3, [R11,#codedata]
libedog.so:5D6950C4 03 00 A0 E1 MOV R0, R3
libedog.so:5D6950C8 04 D0 4B E2 SUB SP, R11, #4
libedog.so:5D6950CC 00 88 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= -8
libedog.so:5D695288
libedog.so:5D695288 00 48 2D E9 STMFD SP!, {R11,LR}
libedog.so:5D69528C 04 B0 8D E2 ADD R11, SP, #4
libedog.so:5D695290 20 D0 4D E2 SUB SP, SP, #0x20
libedog.so:5D695294 18 00 0B E5 STR R0, [R11,#crckey]
libedog.so:5D695298 1C 10 0B E5 STR R1, [R11,#codedata]
libedog.so:5D69529C 20 20 0B E5 STR R2, [R11,#codedata1]
libedog.so:5D6952A0 24 30 0B E5 STR R3, [R11,#codeSize]
libedog.so:5D6952A4 18 30 1B E5 LDR R3, [R11,#crckey]
libedog.so:5D6952A8 14 30 0B E5 STR R3, [R11,#crckey1]
libedog.so:5D6952AC 14 30 4B E2 SUB R3, R11, #-crckey1
libedog.so:5D6952B0 10 30 0B E5 STR R3, [R11,#crckeyaddr]
libedog.so:5D6952B4 00 30 A0 E3 MOV R3, #0
libedog.so:5D6952B8 08 30 0B E5 STR R3, [R11,#index]
libedog.so:5D6952BC 00 30 A0 E3 MOV R3, #0
libedog.so:5D6952C0 0C 30 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D6952C4 00 30 A0 E3 MOV R3, #0
libedog.so:5D6952C8 08 30 0B E5 STR R3, [R11,#index]
libedog.so:5D6952CC 1E 00 00 EA B loc_5D69534C
libedog.so:5D6952D0 ; ---------------------------------------------------------------------------
libedog.so:5D6952D0
libedog.so:5D6952D0 loc_5D6952D0 ; CODE XREF: _Z8XorArrayjPhS_j+E0j
libedog.so:5D6952D0 08 30 1B E5 LDR R3, [R11,#index]
libedog.so:5D6952D4 20 20 1B E5 LDR R2, [R11,#codedata1]
libedog.so:5D6952D8 03 30 82 E0 ADD R3, R2, R3
libedog.so:5D6952DC 08 20 1B E5 LDR R2, [R11,#index]
libedog.so:5D6952E0 1C 10 1B E5 LDR R1, [R11,#codedata]
libedog.so:5D6952E4 02 20 81 E0 ADD R2, R1, R2
libedog.so:5D6952E8 00 10 D2 E5 LDRB R1, [R2]
libedog.so:5D6952EC 0C 20 1B E5 LDR R2, [R11,#crckeyindex]
libedog.so:5D6952F0 10 00 1B E5 LDR R0, [R11,#crckeyaddr]
libedog.so:5D6952F4 02 20 80 E0 ADD R2, R0, R2
libedog.so:5D6952F8 00 20 D2 E5 LDRB R2, [R2]
libedog.so:5D6952FC 02 20 21 E0 EOR R2, R1, R2
libedog.so:5D695300 FF 20 02 E2 AND R2, R2, #0xFF
libedog.so:5D695304 00 20 C3 E5 STRB R2, [R3]
libedog.so:5D695308 0C 30 1B E5 LDR R3, [R11,#crckeyindex]
libedog.so:5D69530C 03 00 53 E3 CMP R3, #3 ; 比较key是否结束
libedog.so:5D695310 07 00 00 1A BNE loc_5D695334
libedog.so:5D695314 14 30 1B E5 LDR R3, [R11,#crckey1]
libedog.so:5D695318 03 00 A0 E1 MOV R0, R3
libedog.so:5D69531C 6C FF FF EB BL _Z10PolyXorKeyj
libedog.so:5D695320 00 30 A0 E1 MOV R3, R0
libedog.so:5D695324 14 30 0B E5 STR R3, [R11,#crckey1]
libedog.so:5D695328 00 30 A0 E3 MOV R3, #0
libedog.so:5D69532C 0C 30 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D695330 02 00 00 EA B loc_5D695340
libedog.so:5D695334 ; ---------------------------------------------------------------------------
libedog.so:5D695334
libedog.so:5D695334 loc_5D695334 ; CODE XREF: _Z8XorArrayjPhS_j+88j
libedog.so:5D695334 0C 30 1B E5 LDR R3, [R11,#crckeyindex]
libedog.so:5D695338 01 30 83 E2 ADD R3, R3, #1
libedog.so:5D69533C 0C 30 0B E5 STR R3, [R11,#crckeyindex]
libedog.so:5D695340
libedog.so:5D695340 loc_5D695340 ; CODE XREF: _Z8XorArrayjPhS_j+A8j
libedog.so:5D695340 08 30 1B E5 LDR R3, [R11,#index]
libedog.so:5D695344 01 30 83 E2 ADD R3, R3, #1
libedog.so:5D695348 08 30 0B E5 STR R3, [R11,#index]
libedog.so:5D69534C
libedog.so:5D69534C loc_5D69534C ; CODE XREF: _Z8XorArrayjPhS_j+44j
libedog.so:5D69534C 24 20 1B E5 LDR R2, [R11,#codeSize]
libedog.so:5D695350 08 30 1B E5 LDR R3, [R11,#index]
libedog.so:5D695354 03 00 52 E1 CMP R2, R3
libedog.so:5D695358 00 30 A0 D3 MOVLE R3, #0
libedog.so:5D69535C 01 30 A0 C3 MOVGT R3, #1
libedog.so:5D695360 FF 30 03 E2 AND R3, R3, #0xFF
libedog.so:5D695364 00 00 53 E3 CMP R3, #0
libedog.so:5D695368 D8 FF FF 1A BNE loc_5D6952D0
libedog.so:5D69536C 04 D0 4B E2 SUB SP, R11, #4
libedog.so:5D695370 00 88 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与解密两个步骤来完成,这里只贴出部分代码详细的请看工程,代码写得比较粗操,看下思路就行了,有性趣的就慢慢撸吧!
Shelling.cpp
// Shelling.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "crc32.h"
#include "dexFile.h"
int _tmain(int argc, _TCHAR* argv[])
{
initDex("classes.dex");
fixdexClassData();
Uninit();
printf("======================修复完成!!!!========\n");
return 0;
}
dexFile.h
#ifndef LIBDEX_DEXFILE_H_
#define LIBDEX_DEXFILE_H_
typedef unsigned long u4;
typedef unsigned short u2;
typedef unsigned char u1;
/* DEX file magic number */
#define DEX_MAGIC "dex\n"
/* current version, encoded in 4 bytes of ASCII */
#define DEX_MAGIC_VERS "036\0"
/*
* older but still-recognized version (corresponding to Android API
* levels 13 and earlier
*/
#define DEX_MAGIC_VERS_API_13 "035\0"
/* same, but for optimized DEX header */
#define DEX_OPT_MAGIC "dey\n"
#define DEX_OPT_MAGIC_VERS "036\0"
#define DEX_DEP_MAGIC "deps"
/*
* 160-bit SHA-1 digest.
*/
enum { kSHA1DigestLen = 20,
kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
/* general constants */
enum {
kDexEndianConstant = 0x12345678, /* the endianness indicator */
kDexNoIndex = 0xffffffff, /* not a valid index value */
};
/*
* Enumeration of all the primitive types.
*/
enum PrimitiveType {
PRIM_NOT = 0, /* value is a reference type, not a primitive type */
PRIM_VOID = 1,
PRIM_BOOLEAN = 2,
PRIM_BYTE = 3,
PRIM_SHORT = 4,
PRIM_CHAR = 5,
PRIM_INT = 6,
PRIM_LONG = 7,
PRIM_FLOAT = 8,
PRIM_DOUBLE = 9,
};
/*
* access flags and masks; the "standard" ones are all <= 0x4000
*
* Note: There are related declarations in vm/oo/Object.h in the ClassFlags
* enum.
*/
enum {
ACC_PUBLIC = 0x00000001, // class, field, method, ic
ACC_PRIVATE = 0x00000002, // field, method, ic
ACC_PROTECTED = 0x00000004, // field, method, ic
ACC_STATIC = 0x00000008, // field, method, ic
ACC_FINAL = 0x00000010, // class, field, method, ic
ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives)
ACC_SUPER = 0x00000020, // class (not used in Dalvik)
ACC_VOLATILE = 0x00000040, // field
ACC_BRIDGE = 0x00000040, // method (1.5)
ACC_TRANSIENT = 0x00000080, // field
ACC_VARARGS = 0x00000080, // method (1.5)
ACC_NATIVE = 0x00000100, // method
ACC_INTERFACE = 0x00000200, // class, ic
ACC_ABSTRACT = 0x00000400, // class, method, ic
ACC_STRICT = 0x00000800, // method
ACC_SYNTHETIC = 0x00001000, // field, method, ic
ACC_ANNOTATION = 0x00002000, // class, ic (1.5)
ACC_ENUM = 0x00004000, // class, field, ic (1.5)
ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only)
ACC_DECLARED_SYNCHRONIZED =
0x00020000, // method (Dalvik only)
ACC_CLASS_MASK =
(ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
| ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
ACC_INNER_CLASS_MASK =
(ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
ACC_FIELD_MASK =
(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
| ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
ACC_METHOD_MASK =
(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
| ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
| ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
| ACC_DECLARED_SYNCHRONIZED),
};
/* annotation constants */
enum {
kDexVisibilityBuild = 0x00, /* annotation visibility */
kDexVisibilityRuntime = 0x01,
kDexVisibilitySystem = 0x02,
kDexAnnotationByte = 0x00,
kDexAnnotationShort = 0x02,
kDexAnnotationChar = 0x03,
kDexAnnotationInt = 0x04,
kDexAnnotationLong = 0x06,
kDexAnnotationFloat = 0x10,
kDexAnnotationDouble = 0x11,
kDexAnnotationString = 0x17,
kDexAnnotationType = 0x18,
kDexAnnotationField = 0x19,
kDexAnnotationMethod = 0x1a,
kDexAnnotationEnum = 0x1b,
kDexAnnotationArray = 0x1c,
kDexAnnotationAnnotation = 0x1d,
kDexAnnotationNull = 0x1e,
kDexAnnotationBoolean = 0x1f,
kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */
kDexAnnotationValueArgShift = 5,
};
/* map item type codes */
enum {
kDexTypeHeaderItem = 0x0000,
kDexTypeStringIdItem = 0x0001,
kDexTypeTypeIdItem = 0x0002,
kDexTypeProtoIdItem = 0x0003,
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
kDexTypeClassDefItem = 0x0006,
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
kDexTypeAnnotationSetItem = 0x1003,
kDexTypeClassDataItem = 0x2000,
kDexTypeCodeItem = 0x2001,
kDexTypeStringDataItem = 0x2002,
kDexTypeDebugInfoItem = 0x2003,
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodedArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006,
};
/* auxillary data section chunk codes */
enum {
kDexChunkClassLookup = 0x434c4b50, /* CLKP */
kDexChunkRegisterMaps = 0x524d4150, /* RMAP */
kDexChunkEnd = 0x41454e44, /* AEND */
};
/* debug info opcodes and constants */
enum {
DBG_END_SEQUENCE = 0x00,
DBG_ADVANCE_PC = 0x01,
DBG_ADVANCE_LINE = 0x02,
DBG_START_LOCAL = 0x03,
DBG_START_LOCAL_EXTENDED = 0x04,
DBG_END_LOCAL = 0x05,
DBG_RESTART_LOCAL = 0x06,
DBG_SET_PROLOGUE_END = 0x07,
DBG_SET_EPILOGUE_BEGIN = 0x08,
DBG_SET_FILE = 0x09,
DBG_FIRST_SPECIAL = 0x0a,
DBG_LINE_BASE = -4,
DBG_LINE_RANGE = 15,
};
/*
* Direct-mapped "header_item" struct.
*/
struct DexHeader {
u1 magic[8]; /* includes version number */
u4 checksum; /* adler32 checksum */
u1 signature[kSHA1DigestLen]; /* SHA-1 hash */
u4 fileSize; /* length of entire file */
u4 headerSize; /* offset to start of next section */
u4 endianTag;
u4 linkSize;
u4 linkOff;
u4 mapOff;
u4 stringIdsSize;
u4 stringIdsOff;
u4 typeIdsSize;
u4 typeIdsOff;
u4 protoIdsSize;
u4 protoIdsOff;
u4 fieldIdsSize;
u4 fieldIdsOff;
u4 methodIdsSize;
u4 methodIdsOff;
u4 classDefsSize;
u4 classDefsOff;
u4 dataSize;
u4 dataOff;
};
/*
* Direct-mapped "map_item".
*/
struct DexMapItem {
u2 type; /* type code (see kDexType* above) */
u2 unused;
u4 size; /* count of items of the indicated type */
u4 offset; /* file offset to the start of data */
};
/*
* Direct-mapped "map_list".
*/
struct DexMapList {
u4 size; /* #of entries in list */
DexMapItem list[1]; /* entries */
};
/*
* Direct-mapped "string_id_item".
*/
struct DexStringId {
u4 stringDataOff; /* file offset to string_data_item */
};
/*
* Direct-mapped "type_id_item".
*/
struct DexTypeId {
u4 descriptorIdx; /* index into stringIds list for type descriptor */
};
/*
* Direct-mapped "field_id_item".
*/
struct DexFieldId {
u2 classIdx; /* index into typeIds list for defining class */
u2 typeIdx; /* index into typeIds for field type */
u4 nameIdx; /* index into stringIds for field name */
};
/*
* Direct-mapped "method_id_item".
*/
struct DexMethodId {
u2 classIdx; /* index into typeIds list for defining class */
u2 protoIdx; /* index into protoIds for method prototype */
u4 nameIdx; /* index into stringIds for method name */
};
/*
* Direct-mapped "proto_id_item".
*/
struct DexProtoId {
u4 shortyIdx; /* index into stringIds for shorty descriptor */
u4 returnTypeIdx; /* index into typeIds list for return type */
u4 parametersOff; /* file offset to type_list for parameter types */
};
/*
* Direct-mapped "class_def_item".
*/
struct DexClassDef {
u4 classIdx; /* index into typeIds for this class */
u4 accessFlags;
u4 superclassIdx; /* index into typeIds for superclass */
u4 interfacesOff; /* file offset to DexTypeList */
u4 sourceFileIdx; /* index into stringIds for source file name */
u4 annotationsOff; /* file offset to annotations_directory_item */
u4 classDataOff; /* file offset to class_data_item */
u4 staticValuesOff; /* file offset to DexEncodedArray */
};
/*
* Direct-mapped "type_item".
*/
struct DexTypeItem {
u2 typeIdx; /* index into typeIds */
};
/*
* Direct-mapped "type_list".
*/
struct DexTypeList {
u4 size; /* #of entries in list */
DexTypeItem list[1]; /* entries */
};
/*
* Direct-mapped "code_item".
*
* The "catches" table is used when throwing an exception,
* "debugInfo" is used when displaying an exception stack trace or
* debugging. An offset of zero indicates that there are no entries.
*/
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[1];
/* followed by optional u2 padding */
/* followed by try_item[triesSize] */
/* followed by uleb128 handlersSize */
/* followed by catch_handler_item[handlersSize] */
};
/*
* Direct-mapped "try_item".
*/
struct DexTry {
u4 startAddr; /* start address, in 16-bit code units */
u2 insnCount; /* instruction count, in 16-bit code units */
u2 handlerOff; /* offset in encoded handler data to handlers */
};
/*
* Link table. Currently undefined.
*/
struct DexLink {
u1 bleargh;
};
/*
* Direct-mapped "annotations_directory_item".
*/
struct DexAnnotationsDirectoryItem {
u4 classAnnotationsOff; /* offset to DexAnnotationSetItem */
u4 fieldsSize; /* count of DexFieldAnnotationsItem */
u4 methodsSize; /* count of DexMethodAnnotationsItem */
u4 parametersSize; /* count of DexParameterAnnotationsItem */
/* followed by DexFieldAnnotationsItem[fieldsSize] */
/* followed by DexMethodAnnotationsItem[methodsSize] */
/* followed by DexParameterAnnotationsItem[parametersSize] */
};
/*
* Direct-mapped "field_annotations_item".
*/
struct DexFieldAnnotationsItem {
u4 fieldIdx;
u4 annotationsOff; /* offset to DexAnnotationSetItem */
};
/*
* Direct-mapped "method_annotations_item".
*/
struct DexMethodAnnotationsItem {
u4 methodIdx;
u4 annotationsOff; /* offset to DexAnnotationSetItem */
};
/*
* Direct-mapped "parameter_annotations_item".
*/
struct DexParameterAnnotationsItem {
u4 methodIdx;
u4 annotationsOff; /* offset to DexAnotationSetRefList */
};
/*
* Direct-mapped "annotation_set_ref_item".
*/
struct DexAnnotationSetRefItem {
u4 annotationsOff; /* offset to DexAnnotationSetItem */
};
/*
* Direct-mapped "annotation_set_ref_list".
*/
struct DexAnnotationSetRefList {
u4 size;
DexAnnotationSetRefItem list[1];
};
/*
* Direct-mapped "annotation_set_item".
*/
struct DexAnnotationSetItem {
u4 size;
u4 entries[1]; /* offset to DexAnnotationItem */
};
/*
* Direct-mapped "annotation_item".
*
* NOTE: this structure is byte-aligned.
*/
struct DexAnnotationItem {
u1 visibility;
u1 annotation[1]; /* data in encoded_annotation format */
};
/*
* Direct-mapped "encoded_array".
*
* NOTE: this structure is byte-aligned.
*/
struct DexEncodedArray {
u1 array[1]; /* data in encoded_array format */
};
/*
* Lookup table for classes. It provides a mapping from class name to
* class definition. Used by dexFindClass().
*
* We calculate this at DEX optimization time and embed it in the file so we
* don't need the same hash table in every VM. This is slightly slower than
* a hash table with direct pointers to the items, but because it's shared
* there's less of a penalty for using a fairly sparse table.
*/
struct DexClassLookup {
int size; // total size, including "size"
int numEntries; // size of table[]; always power of 2
struct {
u4 classDescriptorHash; // class descriptor hash code
int classDescriptorOffset; // in bytes, from start of DEX
int classDefOffset; // in bytes, from start of DEX
} table[1];
};
/*
* Header added by DEX optimization pass. Values are always written in
* local byte and structure padding. The first field (magic + version)
* is guaranteed to be present and directly readable for all expected
* compiler configurations; the rest is version-dependent.
*
* Try to keep this simple and fixed-size.
*/
struct DexOptHeader {
u1 magic[8]; /* includes version number */
u4 dexOffset; /* file offset of DEX header */
u4 dexLength;
u4 depsOffset; /* offset of optimized DEX dependency table */
u4 depsLength;
u4 optOffset; /* file offset of optimized data tables */
u4 optLength;
u4 flags; /* some info flags */
u4 checksum; /* adler32 checksum covering deps/opt */
/* pad for 64-bit alignment if necessary */
};
#define DEX_OPT_FLAG_BIG (1<<1) /* swapped to big-endian */
#define DEX_INTERFACE_CACHE_SIZE 128 /* must be power of 2 */
/*
* Structure representing a DEX file.
*
* Code should regard DexFile as opaque, using the API calls provided here
* to access specific structures.
*/
struct DexFile {
/* directly-mapped "opt" header */
const DexOptHeader* pOptHeader;
/* pointers to directly-mapped structs and arrays in base DEX */
const DexHeader* pHeader;
const DexStringId* pStringIds;
const DexTypeId* pTypeIds;
const DexFieldId* pFieldIds;
const DexMethodId* pMethodIds;
const DexProtoId* pProtoIds;
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
/*
* These are mapped out of the "auxillary" section, and may not be
* included in the file.
*/
const DexClassLookup* pClassLookup;
const void* pRegisterMapPool; // RegisterMapClassPool
/* points to start of DEX file data */
const u1* baseAddr;
/* track memory overhead for auxillary structures */
int overhead;
/* additional app-specific data structures associated with the DEX */
//void* auxData;
};
/* expanded form of a class_data_item header */
struct DexClassDataHeader {
u4 staticFieldsSize;
u4 instanceFieldsSize;
u4 directMethodsSize;
u4 virtualMethodsSize;
};
/* expanded form of encoded_field */
struct DexField {
u4 fieldIdx; /* index to a field_id_item */
u4 accessFlags;
};
/* expanded form of encoded_method */
struct DexMethod {
u4 methodIdx; /* index to a method_id_item */
u4 accessFlags;
u4 codeOff; /* file offset to a code_item */
};
/* expanded form of class_data_item. Note: If a particular item is
* absent (e.g., no static fields), then the corresponding pointer
* is set to NULL. */
struct DexClassData {
DexClassDataHeader header;
DexField* staticFields;
DexField* instanceFields;
DexMethod* directMethods;
DexMethod* virtualMethods;
};
#endif
void fixdexClassData();
void initDex(char* DexFileName);
void Uninit();
// FindDexCode.cpp : Defines the entry point for the console application.
//
#pragma once
#include "stdafx.h"
#include "dexFile.h"
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include "Dec.h"
//DexFile* pDexFile;
HANDLE hMapFile;
HANDLE hFile;
LPVOID lpMapAddress;
DWORD dexsize;
DexFile gDexFile;
u1* gCodeData = NULL;
void initDex(char* DexFileName)
{
hFile = CreateFile(DexFileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("hFile is NULL\n");
printf("Target file is %s\n",
DexFileName);
return ;
}
dexsize = GetFileSize(hFile, NULL);
hMapFile = CreateFileMapping( hFile, // current file handle
NULL, // default security
PAGE_READWRITE, // read/write permission
0, // size of mapping object, high
dexsize, // size of mapping object, low
NULL); // name of mapping object
if (hMapFile == NULL)
{
printf("hMapFile is NULL: last error: %d\n", GetLastError() );
return;
}
// Map the view and test the results.
lpMapAddress = MapViewOfFile(hMapFile, // handle to
// mapping object
FILE_MAP_ALL_ACCESS, // read/write
0, // high-order 32
// bits of file
// offset
0, // low-order 32
// bits of file
// offset
dexsize); // number of bytes
// to map
if (lpMapAddress == NULL)
{
printf("lpMapAddress is NULL: last error: %d\n", GetLastError());
return ;
}
// pDexFile = new DexFile;
void *dexBase = lpMapAddress;
DexHeader *dexHeader = (DexHeader *)dexBase;
gDexFile.baseAddr = (u1*)dexBase;
gDexFile.pHeader = dexHeader;
gDexFile.pStringIds = (DexStringId*)((u4)dexBase+dexHeader->stringIdsOff);
gDexFile.pTypeIds = (DexTypeId*)((u4)dexBase+dexHeader->typeIdsOff);
gDexFile.pMethodIds = (DexMethodId*)((u4)dexBase+dexHeader->methodIdsOff);
gDexFile.pFieldIds = (DexFieldId*)((u4)dexBase+dexHeader->fieldIdsOff);
gDexFile.pClassDefs = (DexClassDef*)((u4)dexBase+dexHeader->classDefsOff);
gDexFile.pProtoIds = (DexProtoId*)((u4)dexBase+dexHeader->protoIdsOff);
}
void Uninit()
{
UnmapViewOfFile(lpMapAddress);
CloseHandle(hFile);
if (NULL != gCodeData)
{
free(gCodeData);
gCodeData = NULL;
}
}
//-------------------------------------------------
static void getAccessFlags(char *buf, int flags)
{
if((flags & ACC_PUBLIC) != 0) strcat(buf, "public ");
if((flags & ACC_PRIVATE) != 0) strcat(buf, "private ");
if((flags & ACC_PROTECTED) != 0) strcat(buf, "protected ");
if((flags & ACC_STATIC) != 0) strcat(buf, "static ");
if((flags & ACC_FINAL) != 0) strcat(buf, "final ");
if((flags & ACC_SYNCHRONIZED) != 0) strcat(buf, "synchronized ");
if((flags & ACC_SUPER) != 0) strcat(buf, "super ");
if((flags & ACC_VOLATILE) != 0) strcat(buf, "volatile ");
if((flags & ACC_BRIDGE) != 0) strcat(buf, "bridge ");
if((flags & ACC_TRANSIENT) != 0) strcat(buf, "transient ");
if((flags & ACC_VARARGS) != 0) strcat(buf, "varargs ");
if((flags & ACC_NATIVE) != 0) strcat(buf, "native ");
if((flags & ACC_INTERFACE) != 0) strcat(buf, "interface ");
if((flags & ACC_ABSTRACT) != 0) strcat(buf, "abstract ");
if((flags & ACC_STRICT) != 0) strcat(buf, "strict ");
if((flags & ACC_SYNTHETIC) != 0) strcat(buf, "synthetic ");
if((flags & ACC_ANNOTATION) != 0) strcat(buf, "annotation ");
if((flags & ACC_ENUM) != 0) strcat(buf, "enum ");
if((flags & ACC_CONSTRUCTOR) != 0) strcat(buf, "constructor ");
if((flags & ACC_DECLARED_SYNCHRONIZED) != 0) strcat(buf, "synchronize ");
}
static int readUnsignedLeb128(const u1** pStream) {
const u1* ptr = *pStream;
int result = *(ptr++);
if (result > 0x7f) {
int cur = *(ptr++);
result = (result & 0x7f) | ((cur & 0x7f) << 7);
if (cur > 0x7f) {
cur = *(ptr++);
result |= (cur & 0x7f) << 14;
if (cur > 0x7f) {
cur = *(ptr++);
result |= (cur & 0x7f) << 21;
if (cur > 0x7f) {
/*
* Note: We don't check to see if cur is out of
* range here, meaning we tolerate garbage in the
* high four-order bits.
*/
cur = *(ptr++);
result |= cur << 28;
}
}
}
}
*pStream = ptr;
return result;
}
static DexCode* dexGetCode(DexFile* pDexFile,
const DexMethod* pDexMethod)
{
if (pDexMethod->codeOff == 0)
return NULL;
return (DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff);
}
/* return the ClassDef with the specified index */
static const DexClassDef* dexGetClassDef(const DexFile* pDexFile, u4 idx) {
assert(idx < pDexFile->pHeader->classDefsSize);
return &pDexFile->pClassDefs[idx];
}
/* Read the header of a class_data_item without verification. This
* updates the given data pointer to point past the end of the read
* data. */
static void dexReadClassDataHeader(const u1** pData,
DexClassDataHeader *pHeader) {
pHeader->staticFieldsSize = readUnsignedLeb128(pData);
pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
pHeader->directMethodsSize = readUnsignedLeb128(pData);
pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
}
/* Read an encoded_field without verification. This updates the
* given data pointer to point past the end of the read data.
*
* The lastIndex value should be set to 0 before the first field in
* a list is read. It is updated as fields are read and used in the
* decode process.
*/
static void dexReadClassDataField(const u1** pData, DexField* pField,
u4* lastIndex) {
u4 index = *lastIndex + readUnsignedLeb128(pData);
pField->accessFlags = readUnsignedLeb128(pData);
pField->fieldIdx = index;
*lastIndex = index;
}
/* Read an encoded_method without verification. This updates the
* given data pointer to point past the end of the read data.
*
* The lastIndex value should be set to 0 before the first method in
* a list is read. It is updated as fields are read and used in the
* decode process.
*/
static void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod,
u4* lastIndex) {
u4 index = *lastIndex + readUnsignedLeb128(pData);
pMethod->accessFlags = readUnsignedLeb128(pData);
pMethod->codeOff = readUnsignedLeb128(pData);
pMethod->methodIdx = index;
*lastIndex = index;
}
static char *getString(const DexFile *dexFile, int id)
{
return (char *)(dexFile->baseAddr + dexFile->pStringIds[id].stringDataOff+1);
}
static int getTypeIdStringId(const DexFile *dexFile, int id)
{
const DexTypeId *typeId = dexFile->pTypeIds;
return typeId[id].descriptorIdx;
}
#define getTpyeIdString(dexFile, id) getString((dexFile), getTypeIdStringId((dexFile),(id)))
static u1 *getClassDataPtr(const DexFile *dexFile, int idx)
{
return (u1 *)(dexFile->baseAddr + dexFile->pClassDefs[idx].classDataOff);
}
static void dumpDexHeader(DexHeader *header)
{
printf("[Dex Header] headerSize:0x%08lx fileSize:0x%08lx", header->headerSize, header->fileSize);
printf("[Dex Header] linkSize:0x%08lx linkOff:0x%08lx mapOff:0x%08lx", header->linkSize, header->linkOff, header->mapOff);
printf("[Dex Header] StringIds size:0x%08lx offset:0x%08lx", header->stringIdsSize, header->stringIdsOff);
printf("[Dex Header] TypeIds size:0x%08lx offset:0x%08lx", header->typeIdsSize, header->typeIdsOff);
printf("[Dex Header] ProtoIds size:0x%08lx offset:0x%08lx", header->protoIdsSize, header->protoIdsOff);
printf("[Dex Header] FieldIds size:0x%08lx offset:0x%08lx", header->fieldIdsSize, header->fieldIdsOff);
printf("[Dex Header] MethodIds size:0x%08lx offset:0x%08lx", header->methodIdsSize, header->methodIdsOff);
printf("[Dex Header] ClassDefs size:0x%08lx offset:0x%08lx", header->classDefsSize, header->classDefsOff);
printf("[Dex Header] Data size:0x%08lx offset:0x%08lx", header->dataSize, header->dataOff);
}
static void dumpDexStrings(const DexFile *dexFile)
{
int i =0;
char *str;
int count = dexFile->pHeader->stringIdsSize;
for(i=0; i<count; i++){
str = (char *)(dexFile->baseAddr + dexFile->pStringIds[i].stringDataOff);
printf("[Strings] id=%d [%d]:%s", i, str[0], str+1);
}
}
static void dumpDexTypeIds(const DexFile *dexFile)
{
const DexTypeId *typeId = dexFile->pTypeIds;
int count = dexFile->pHeader->typeIdsSize;
for(int i=0; i<count; i++){
printf("[types] [%d] %s", i, getString(dexFile, typeId[i].descriptorIdx));
}
}
static void dumpFieldIds(const DexFile *dexFile)
{
const DexFieldId *pfield = dexFile->pFieldIds;
int count = dexFile->pHeader->fieldIdsSize;
for(int i=0; i<count; i++){
printf("[field] %s -> %s %s",
getTpyeIdString(dexFile, pfield[i].classIdx),
getString(dexFile, pfield[i].nameIdx),
getTpyeIdString(dexFile, pfield[i].typeIdx));
}
}
static void dumpDexProtos(const DexFile *dexFile)
{
char buffer[1024];
const DexProtoId *proto = dexFile->pProtoIds;
int count = dexFile->pHeader->protoIdsSize;
DexTypeList *plist;
for(int i=0; i<count; i++){
sprintf(buffer, "[proto] %d short:", i);
strcat(buffer, getString(dexFile, proto[i].shortyIdx));
strcat(buffer, " return:");
strcat(buffer, getTpyeIdString(dexFile, proto[i].returnTypeIdx));
if(proto[i].parametersOff == 0){
printf("%s", buffer);
continue;
}
strcat(buffer, " param:");
plist = (DexTypeList *)(dexFile->baseAddr + proto[i].parametersOff);
for(u4 j=0; j<plist->size; j++){
strcat(buffer, getTpyeIdString(dexFile, plist->list[j].typeIdx));
}
printf("%s", buffer);
}
}
static void dumpClassDefines(const DexFile *dexFile)
{
char buffer[1024];
const DexClassDef* classdef = dexFile->pClassDefs;
int count = dexFile->pHeader->classDefsSize;
buffer[0] = 0;
for(int i=0; i<count; i++){
getAccessFlags(buffer, classdef[i].accessFlags);
strcat(buffer, " class ");
strcat(buffer, getTpyeIdString(dexFile, classdef[i].classIdx));
strcat(buffer, " externds ");
strcat(buffer, getTpyeIdString(dexFile, classdef[i].superclassIdx));
strcat(buffer, " implements ");
//strcat(buffer, getTpyeIdString(dexFile, classdef[i].interfacesOff);
printf("%s", buffer);
}
}
static void dumpMethodIds(const DexFile *dexFile)
{
const DexMethodId *pmethod = dexFile->pMethodIds;
}
static int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit,
bool* okay) {
const u1* ptr = *pStream;
int result = readUnsignedLeb128(pStream);
if (((limit != NULL) && (*pStream > limit))
|| (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) {
*okay = false;
}
return result;
}
/* Helper for verification which reads and verifies a given number
* of uleb128 values. */
static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) {
bool okay = true;
u4 i;
while (okay && (count-- != 0)) {
readAndVerifyUnsignedLeb128(&pData, pLimit, &okay);
}
return okay;
}
/* Read and verify the header of a class_data_item. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure). */
static bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
DexClassDataHeader *pHeader) {
if (! verifyUlebs(*pData, pLimit, 4)) {
return false;
}
dexReadClassDataHeader(pData, pHeader);
/* printf("ClassHeader: field: s-%ld i-%ld method: d-%ld v-%ld",
pHeader->staticFieldsSize, pHeader->instanceFieldsSize,
pHeader->directMethodsSize, pHeader->staticFieldsSize);*/
return true;
}
/* Read and verify an encoded_field. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
*
* The lastIndex value should be set to 0 before the first field in
* a list is read. It is updated as fields are read and used in the
* decode process.
*
* The verification done by this function is of the raw data format
* only; it does not verify that access flags or indices
* are valid. */
static bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
DexField* pField, u4* lastIndex) {
if (! verifyUlebs(*pData, pLimit, 2)) {
return false;
}
dexReadClassDataField(pData, pField, lastIndex);
return true;
}
/* Read and verify an encoded_method. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
*
* The lastIndex value should be set to 0 before the first method in
* a list is read. It is updated as fields are read and used in the
* decode process.
*
* The verification done by this function is of the raw data format
* only; it does not verify that access flags, indices, or offsets
* are valid. */
static bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
DexMethod* pMethod, u4* lastIndex) {
if (! verifyUlebs(*pData, pLimit, 3)) {
return false;
}
dexReadClassDataMethod(pData, pMethod, lastIndex);
return true;
}
/* Read, verify, and return an entire class_data_item. This updates
* the given data pointer to point past the end of the read data. This
* function allocates a single chunk of memory for the result, which
* must subsequently be free()d. This function returns NULL if there
* was trouble parsing the data. If this function is passed NULL, it
* returns an initialized empty DexClassData structure.
*
* The verification done by this function is of the raw data format
* only; it does not verify that access flags, indices, or offsets
* are valid. */
static DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) {
DexClassDataHeader header;
u4 lastIndex;
if (*pData == NULL) {
DexClassData* result = (DexClassData*) malloc(sizeof(DexClassData));
memset(result, 0, sizeof(*result));
return result;
}
if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) {
return NULL;
}
size_t resultSize = sizeof(DexClassData) +
(header.staticFieldsSize * sizeof(DexField)) +
(header.instanceFieldsSize * sizeof(DexField)) +
(header.directMethodsSize * sizeof(DexMethod)) +
(header.virtualMethodsSize * sizeof(DexMethod));
DexClassData* result = (DexClassData*) malloc(resultSize);
u1* ptr = ((u1*) result) + sizeof(DexClassData);
bool okay = true;
u4 i;
if (result == NULL) {
return NULL;
}
result->header = header;
if (header.staticFieldsSize != 0) {
result->staticFields = (DexField*) ptr;
ptr += header.staticFieldsSize * sizeof(DexField);
} else {
result->staticFields = NULL;
}
if (header.instanceFieldsSize != 0) {
result->instanceFields = (DexField*) ptr;
ptr += header.instanceFieldsSize * sizeof(DexField);
} else {
result->instanceFields = NULL;
}
if (header.directMethodsSize != 0) {
result->directMethods = (DexMethod*) ptr;
ptr += header.directMethodsSize * sizeof(DexMethod);
} else {
result->directMethods = NULL;
}
if (header.virtualMethodsSize != 0) {
result->virtualMethods = (DexMethod*) ptr;
} else {
result->virtualMethods = NULL;
}
lastIndex = 0;
for (i = 0; okay && (i < header.staticFieldsSize); i++) {
okay = dexReadAndVerifyClassDataField(pData, pLimit,
&result->staticFields[i], &lastIndex);
}
lastIndex = 0;
for (i = 0; okay && (i < header.instanceFieldsSize); i++) {
okay = dexReadAndVerifyClassDataField(pData, pLimit,
&result->instanceFields[i], &lastIndex);
}
lastIndex = 0;
for (i = 0; okay && (i < header.directMethodsSize); i++) {
okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
&result->directMethods[i], &lastIndex);
}
lastIndex = 0;
for (i = 0; okay && (i < header.virtualMethodsSize); i++) {
okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
&result->virtualMethods[i], &lastIndex);
}
if (! okay) {
free(result);
return NULL;
}
return result;
}
static void dumpDexClassDataMethod(DexFile *dexFile, DexClassData* classData)
{
int idx = 0;
DexMethod *method = NULL;
const DexMethodId* methodId = NULL;
method = classData->directMethods;
methodId = dexFile->pMethodIds;
for (int i = 0; i < (int) classData->header.directMethodsSize; i++) {
idx = classData->directMethods[i].methodIdx;
DexCode* pCode = dexGetCode(dexFile, &classData->directMethods[i]);
if(pCode == NULL) continue;
//ALOGD(" registers : %d", pCode->registersSize);
// ALOGD(" ins : %d", pCode->insSize);
// ALOGD(" outs : %d", pCode->outsSize);
// ALOGD(" insns size : %d 16-bit code units", pCode->insnsSize);
int a = 0;
char buffer[256] = {0, 0};
char tmp[32];
for(u4 k=0; k<pCode->insnsSize; k++){
sprintf(tmp, "%04x ", pCode->insns[k]);
strcat(buffer, tmp);
if(k%8 == 7){
printf("%s", buffer);
buffer[0] = 0;
}
}
printf("%s", buffer);
}
for (int i = 0; i < (int) classData->header.virtualMethodsSize; i++) {
idx = classData->virtualMethods[i].methodIdx;
printf("idx-%d [%06lx]: %s->%s", idx, classData->virtualMethods[i].codeOff,
getTpyeIdString(dexFile, methodId[idx].classIdx), getString(dexFile, methodId[idx].nameIdx));
const DexCode* pCode = dexGetCode(dexFile, &classData->virtualMethods[i]);
if(pCode == NULL) continue;
printf(" registers : %d", pCode->registersSize);
printf(" ins : %d", pCode->insSize);
printf(" outs : %d", pCode->outsSize);
printf(" insns size : %ld 16-bit code units", pCode->insnsSize);
printf(" insns at : %x ", (int)(pCode->insns) - (int)dexFile->baseAddr);
printf("%x %x %x %x", pCode->insns[0], pCode->insns[1], pCode->insns[2], pCode->insns[3]);
int a = 0;
char buffer[256] = {0, 0};
char tmp[32];
for(u4 k=0; k<pCode->insnsSize; k++){
sprintf(tmp, "%04x ", pCode->insns[k]);
strcat(buffer, tmp);
if(k%8 == 7){
printf("%s", buffer);
buffer[0] = 0;
}
}
printf("%s", buffer);
}
}
const DexStringId* dexGetStringId(const DexFile* pDexFile, u4 idx) {
return &pDexFile->pStringIds[idx];
}
const char* dexGetStringData(const DexFile* pDexFile,const DexStringId* pStringId)
{
const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
return (const char*) ptr;
}
const char* dexStringById(const DexFile* pDexFile, u4 idx) {
const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
return dexGetStringData(pDexFile, pStringId);
}
const DexMethodId* dexGetMethodId(const DexFile* pDexFile, u4 idx) {
return &pDexFile->pMethodIds[idx];
}
void FixdexMethodInsns(DexFile *dexFile, const DexClassData*classData ,const char* className)
{
int idx = 0;
DexMethod *method = NULL;
const DexMethodId* methodId = NULL;
DexCode* code = NULL;
const char* methodName;
method = classData->directMethods;
methodId = dexFile->pMethodIds;
unsigned int CodeDataOffset = 0;
u1 * tempCode = NULL;
for (int i = 0; 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[0] == 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 = 0; 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[0] == 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;
}
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, 0, FileSize);
//获得加密指令数据
GetCodeData(gCodeData, FileSize);
if (NULL == gCodeData)
{
printf("获取加密指令数据出错!\n");
return;
}
for(u4 i=0; 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);
}
}
static void dumpDexCode(const DexCode *pCode)
{
printf(" registers : %d", pCode->registersSize);
printf(" ins : %d", pCode->insSize);
printf(" outs : %d", pCode->outsSize);
printf(" insns size : %ld 16-bit code units", pCode->insnsSize);
int a = 0;
char buffer[256] = {0, 0};
char tmp[32];
for(u4 k=0; k<pCode->insnsSize; k++){
sprintf(tmp, "%04x ", pCode->insns[k]);
strcat(buffer, tmp);
if(k%8 == 7){
printf("%s", buffer);
buffer[0] = 0;
}
}
printf("%s", buffer);
}
static void handleDexMethod(DexClassData* classData, const char*method)
{
// TODO
}
void* searchDexStart(const void *base)
{
DexOptHeader *optHeader = (DexOptHeader*)base;
return (void*)((u4)base + optHeader->dexOffset);
}
static bool checkDexMagic(const void *dexBase)
{
const char *pattern = "dex\n035";
const char *dexer = (const char *)dexBase;
if(strcmp(dexer, pattern) == 0){
return true;
}
return false;
}
Dec.h
#include <windows.h>
#include "dexFile.h"
unsigned int PolyXorKey(DWORD crckey);
u1* DecCode(u1 *code, int codeSize, DWORD key, u1* oldCode);
void GetCodeData( u1* outdata, int FileSize);
int file_size();
unsigned __int8 * dbone_crypt_ins(unsigned int DebugInfo1, unsigned __int8 *CodeData, unsigned int CodeLen, int Mode);
Dec.cpp
#include "Dec.h"
#include "crc32.h"
#include<stdio.h>
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 = 0;
temp3 = 0;
pKey = (char *)&dwKey;
temp2 = 0;
temp1 = 0;
temp = 0;
dwKey = crckey ^ 0xDF138530;
i = 0;
while ( i <= 3 )
{
temp2 = *pKey;
j = 128;
temp3 = 7;
while ( j > 1 )
{
temp = (temp2 & j / 2) >> (temp3 - 1);
temp1 = ((signed int)(unsigned __int8)(temp2 & j) >> temp3) ^ temp;
temp1 <<= temp3;
temp2 |= temp1;
j /= 2;
--temp3;
}
temp = temp2 & 1;
temp1 = temp2 & 1 ^ temp2 & 1;
*pKey = temp2;
++i;
++pKey;
}
return dwKey;
}
//crc32 FE 00 00 20 = 0x200000FE = 7C939E40
u1* DecCode(u1 *code, int codeSize, DWORD key, u1* oldData)
{
unsigned long Polykey = 0;
unsigned long crc2 = 0;
u1 * tempcode = NULL;
u1 * tempcode1 = NULL;
if (NULL == code || 0 == codeSize || NULL == oldData)
{
return NULL;
}
tempcode = (u1*)malloc(codeSize);
if (NULL == tempcode)
{
return NULL;
}
memset(tempcode, 0, codeSize);
tempcode1 = oldData;
DWORD CodeOffset = *(DWORD*)code;//得到加密指令偏移
tempcode1 += CodeOffset;//定位到加密指令开始位置
memcpy(tempcode, tempcode1, codeSize);
crc2 = crc32(crc2, (unsigned char*)&key, 4);
for (int j=0; j<codeSize; j++)
{
//每4字节进行解密
for (int i =0; i<4; i++)
{
tempcode[j+i] ^= *((unsigned char*)(&crc2)+i);
tempcode[j+i] &= 0XFF;
if (i==3)
{
Polykey = PolyXorKey(crc2);
crc2 = Polykey;
}
}
j += 3;
}
return tempcode;
}
int file_size()
{
FILE * fp;
if( (fp=fopen("data","rb")) == NULL )
{
printf("打开文件失败!\n");
return NULL;
}
fseek(fp,0L,SEEK_END);
int size=ftell(fp);
fclose(fp);
return size;
}
void GetCodeData( u1* outdata, int FileSize)
{
FILE * fp;
if (0 == FileSize || NULL == outdata)
{
return;
}
if( (fp=fopen("data","rb")) == NULL )
{
printf("打开文件失败!\n");
return;
}
fread(outdata,FileSize,1,fp);
fclose(fp);
return;
}
int * XorArray(int *key, int codedata, int outcodedata, int codesize)
{
int v4; // [sp+0h] [bp-24h]@1
int v5; // [sp+4h] [bp-20h]@1
int codedata1; // [sp+8h] [bp-1Ch]@1
int *key1; // [sp+10h] [bp-14h]@1
int *key2; // [sp+14h] [bp-10h]@1
int keyindex; // [sp+18h] [bp-Ch]@1
int i; // [sp+1Ch] [bp-8h]@1
codedata1 = codedata;
v5 = outcodedata;
v4 = codesize;
key1 = key;
key2 = (int *)&key1;
keyindex = 0;
for ( i = 0; v4 > i; ++i )
{
key = key2;
*(BYTE *)(v5 + i) = *(BYTE *)(codedata1 + i) ^ *((BYTE *)key2 + keyindex);
if ( keyindex == 3 )
{
key = (int *)((int *(*)(unsigned int))PolyXorKey)((unsigned int)key1);
key1 = key;
keyindex = 0;
}
else
{
++keyindex;
}
}
return key;
}
int XorArray_0x99(int key, int codedata, int outcodedata, int codelen)
{
int v4; // [sp+10h] [bp-14h]@1
int v5; // [sp+14h] [bp-10h]@1
int *v6; // [sp+18h] [bp-Ch]@1
int i; // [sp+1Ch] [bp-8h]@1
v4 = key;
v6 = &v4;
v5 = 0;
for ( i = 0; codelen > i; ++i )
*(BYTE *)(outcodedata + i) = ~(*(BYTE *)(codedata + i) ^ 0x66);
return key;
}
unsigned __int8 * dbone_crypt_ins(unsigned int DebugInfo1, unsigned __int8 *CodeData, unsigned int CodeLen, int Mode)
{
int mode; // [sp+0h] [bp-1Ch]@1
int codelen; // [sp+4h] [bp-18h]@1
unsigned __int8 *codedata; // [sp+8h] [bp-14h]@1
int DebugInfo; // [sp+Ch] [bp-10h]@1
int crc2key; // [sp+14h] [bp-8h]@1
DebugInfo = DebugInfo1;
codedata = CodeData;
codelen = CodeLen;
mode = Mode;
crc2key = crc32(crc2key, (unsigned char*)&DebugInfo, 4);;
if ( mode == 1 )
{
XorArray(&crc2key, (int)codedata, (int)codedata, codelen);
}
else if ( mode )
{
puts("USAGE:dbone_crypt_ins(key,ins,ins_lenth)");
}
else
{
XorArray_0x99(DebugInfo, (int)codedata, (int)codedata, codelen);
}
return codedata;
}
crc32.h
#include <windows.h>
#include <stdio.h>
static const unsigned long crc_table[256] =
{
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
0x2d02ef8dUL
};
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len);
crc32.cpp
#include "stdafx.h"
#include "crc32.h"
#include <windows.h>
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len)
{
if (NULL == buf)
return 0UL;
crc = crc ^ 0xffffffffUL;
unsigned n = 0;
for (n = 0; n < len; n++)
{
crc = crc_table[(crc ^ buf[n]) & 0xff] ^ (crc >> 8);
}
return crc ^ 0xffffffffUL;
}
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文档下载