APK加固之类抽取分析与修复"/>
APK加固之类抽取分析与修复
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_d1libedog.so:5D692C18libedog.so:5D692C18 var_F0= -0xF0libedog.so:5D692C18 var_EC= -0xEClibedog.so:5D692C18 var_E4= -0xE4libedog.so:5D692C18 var_1C= -0x1Clibedog.so:5D692C18 arg_0= 0libedog.so:5D692C18libedog.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, #0xDClibedog.so:5D692C1E 00 93 STR R3, [SP,#0xF0+var_F0]libedog.so:5D692C20 7F 44 ADD R7, PC ; dword_5D6A5E60libedog.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, R0libedog.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, #0xA9libedog.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, #2libedog.so:5D692C34 22 4D LDR R5, =(aFjFj0fjFjFj4fj - 0x5D692C42)libedog.so:5D692C36 5B 58 LDR R3, [R3,R1]libedog.so:5D692C38 11 1C MOVS R1, R2libedog.so:5D692C3A 00 22 MOVS R2, #0libedog.so:5D692C3C 98 47 BLX R3libedog.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, R4libedog.so:5D692C48 00 F0 5C F8 BL _Z17ANDROID_API_LEVELP7_JNIEnvlibedog.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, R4libedog.so:5D692C54 00 F0 82 F8 BL _Z24ANDROID_PLATFORM_VERSIONP7_JNIEnvlibedog.so:5D692C58 20 1C MOVS R0, R4libedog.so:5D692C5A 00 F0 A9 F8 BL _Z22ANDROID_PLATFORM_MODELP7_JNIEnvlibedog.so:5D692C5E 20 1C MOVS R0, R4libedog.so:5D692C60 00 F0 D0 F8 BL _Z22ANDROID_PLATFORM_BRANDP7_JNIEnvlibedog.so:5D692C64 20 1C MOVS R0, R4libedog.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_E4libedog.so:5D692C72 79 44 ADD R1, PC ; "/data/data/%s/lib/libfdog.so"libedog.so:5D692C74 FF F7 B0 EE BLX sprintflibedog.so:5D692C78 03 A8 ADD R0, SP, #0xF0+var_E4libedog.so:5D692C7A 01 1C MOVS R1, R0libedog.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, #0x2A4libedog.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, R4libedog.so:5D692C90 00 22 MOVS R2, #0libedog.so:5D692C92 98 47 BLX R3libedog.so:5D692C94 0D 49 LDR R1, =(unk_5D6A2A0D - 0x5D692C9A)libedog.so:5D692C96 79 44 ADD R1, PClibedog.so:5D692C98 FF F7 A4 EE BLX strstrlibedog.so:5D692C9C 00 28 CMP R0, #0libedog.so:5D692C9E 02 D1 BNE loc_5D692CA6libedog.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:5D692CA6libedog.so:5D692CA6 loc_5D692CA6 ; CODE XREF: Java_com_edog_ELibrary_d1+86jlibedog.so:5D692CA6 01 20 MOVS R0, #1libedog.so:5D692CA8libedog.so:5D692CA8 loc_5D692CA8 ; CODE XREF: Java_com_edog_ELibrary_d1+8Cjlibedog.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, R3libedog.so:5D692CB2 01 D0 BEQ loc_5D692CB8libedog.so:5D692CB4 FF F7 9C EE BLX sub_5D6929F0libedog.so:5D692CB8 ; ---------------------------------------------------------------------------libedog.so:5D692CB8libedog.so:5D692CB8 loc_5D692CB8 ; CODE XREF: Java_com_edog_ELibrary_d1+9Ajlibedog.so:5D692CB8 37 B0 ADD SP, SP, #0xDClibedog.so:5D692CBA F0 BD POP {R4-R7,PC}libedog.so:5D692CBA ; End of function Java_com_edog_ELibrary_d1libedog.so:5D692CBAlibedog.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:5D693144libedog.so:5D693144 _Z13restoreMethodP11ClassObjectP6Method ; CODE XREF: _Z10replaceFunP11ClassObjectjb+22plibedog.so:5D693144 ; _Z10replaceFunP11ClassObjectjb+3Aplibedog.so:5D693144libedog.so:5D693144 var_34= -0x34libedog.so:5D693144 Debug_info= -0x30libedog.so:5D693144 var_2C= -0x2Clibedog.so:5D693144 codeSize= -0x28libedog.so:5D693144 data= -0x24libedog.so:5D693144 codeoffset= -0x1Clibedog.so:5D693144libedog.so:5D693144 F0 B5 PUSH {R4-R7,LR}libedog.so:5D693146 89 B0 SUB SP, SP, #0x24libedog.so:5D693148 0F 1E SUBS R7, R1, #0libedog.so:5D69314A 5C D0 BEQ loc_5D693206libedog.so:5D69314C 84 69 LDR R4, [R0,#0x18]libedog.so:5D69314E 00 2C CMP R4, #0libedog.so:5D693150 59 D0 BEQ loc_5D693206libedog.so:5D693152 20 1C MOVS R0, R4libedog.so:5D693154 4C 21 MOVS R1, #'L'libedog.so:5D693156 FF F7 A0 EC BLX strchrlibedog.so:5D69315A 00 28 CMP R0, #0libedog.so:5D69315C 53 D0 BEQ loc_5D693206libedog.so:5D69315E 3E 6A LDR R6, [R7,#0x20]libedog.so:5D693160 00 2E CMP R6, #0libedog.so:5D693162 50 D0 BEQ loc_5D693206libedog.so:5D693164 35 1C MOVS R5, R6libedog.so:5D693166 10 3D SUBS R5, #0x10libedog.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, =0x1FFFFFFFlibedog.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_5D693206libedog.so:5D69317C 24 49 LDR R1, =(aLandroid - 0x5D693184)libedog.so:5D69317E 20 1C MOVS R0, R4libedog.so:5D693180 79 44 ADD R1, PC ; "Landroid/"libedog.so:5D693182 FF F7 30 EC BLX strstr ; 是系统的类就跳过libedog.so:5D693186 00 28 CMP R0, #0libedog.so:5D693188 3D D1 BNE loc_5D693206libedog.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, #0libedog.so:5D693190 39 D1 BNE loc_5D693206libedog.so:5D693192 20 4B LDR R3, =(aFjFj0fjFjFj4fj+0xC - 0x5D69319C)libedog.so:5D693194 07 A8 ADD R0, SP, #0x38+codeoffsetlibedog.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, #8libedog.so:5D6931A6 89 09 LSRS R1, R1, #6libedog.so:5D6931A8 89 18 ADDS R1, R1, R2libedog.so:5D6931AA 04 22 MOVS R2, #4libedog.so:5D6931AC FF F7 68 EC BLX memcpy_0libedog.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, #2libedog.so:5D6931B6 08 34 ADDS R4, #8libedog.so:5D6931B8 E4 18 ADDS R4, R4, R3libedog.so:5D6931BA 13 1C MOVS R3, R2libedog.so:5D6931BC 01 33 ADDS R3, #1libedog.so:5D6931BE 9B 00 LSLS R3, R3, #2libedog.so:5D6931C0 E4 18 ADDS R4, R4, R3libedog.so:5D6931C2 64 00 LSLS R4, R4, #1libedog.so:5D6931C4 20 1C MOVS R0, R4libedog.so:5D6931C6 FF F7 26 EC BLX malloclibedog.so:5D6931CA 22 1C MOVS R2, R4libedog.so:5D6931CC 06 1C MOVS R6, R0libedog.so:5D6931CE 01 99 LDR R1, [SP,#0x38+var_34]libedog.so:5D6931D0 FF F7 5C EC BLX memset_0libedog.so:5D6931D4 29 1C MOVS R1, R5libedog.so:5D6931D6 22 1C MOVS R2, R4libedog.so:5D6931D8 30 1C MOVS R0, R6libedog.so:5D6931DA FF F7 52 EC BLX memcpy_0libedog.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, #1libedog.so:5D6931E6 02 98 LDR R0, [SP,#0x38+Debug_info]libedog.so:5D6931E8 51 18 ADDS R1, R2, R1libedog.so:5D6931EA 01 23 MOVS R3, #1libedog.so:5D6931EC 2A 1C MOVS R2, R5libedog.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, R6libedog.so:5D6931F6 10 34 ADDS R4, #0x10libedog.so:5D6931F8 01 1C MOVS R1, R0libedog.so:5D6931FA B3 60 STR R3, [R6,#8] ; 清空Debug_infolibedog.so:5D6931FC 20 1C MOVS R0, R4libedog.so:5D6931FE 2A 1C MOVS R2, R5libedog.so:5D693200 FF F7 3E EC BLX memcpy_0 ; 还原指令libedog.so:5D693204 3C 62 STR R4, [R7,#0x20]libedog.so:5D693206libedog.so:5D693206 loc_5D693206 ; CODE XREF: _Z13restoreMethodP11ClassObjectP6Method+6jlibedog.so:5D693206 ; _Z13restoreMethodP11ClassObjectP6Method+Cj ...libedog.so:5D693206 09 B0 ADD SP, SP, #0x24libedog.so:5D693208 F0 BD POP {R4-R7,PC}libedog.so:5D693208 ; End of function _Z13restoreMethodP1解密指令libedog.so:5D69502Clibedog.so:5D69502C dbone_crypt_ins ; CODE XREF: _Z13restoreMethodP11ClassObjectP6Method+AAplibedog.so:5D69502Clibedog.so:5D69502C DecMode= -0x1Clibedog.so:5D69502C codeSize= -0x18libedog.so:5D69502C codedata= -0x14libedog.so:5D69502C key= -0x10libedog.so:5D69502C crckey= -8libedog.so:5D69502Clibedog.so:5D69502C 00 48 2D E9 STMFD SP!, {R11,LR}libedog.so:5D695030 04 B0 8D E2 ADD R11, SP, #4libedog.so:5D695034 18 D0 4D E2 SUB SP, SP, #0x18libedog.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] ; 1libedog.so:5D695048 10 30 4B E2 SUB R3, R11, #-keylibedog.so:5D69504C 03 00 A0 E1 MOV R0, R3libedog.so:5D695050 04 10 A0 E3 MOV R1, #4libedog.so:5D695054 47 01 00 EB BL _Z5crc32Phjlibedog.so:5D695058 00 30 A0 E1 MOV R3, R0libedog.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, #1libedog.so:5D695068 06 00 00 1A BNE loc_5D695088libedog.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, R2libedog.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_jlibedog.so:5D695084 0D 00 00 EA B loc_5D6950C0libedog.so:5D695088 ; ---------------------------------------------------------------------------libedog.so:5D695088libedog.so:5D695088 loc_5D695088 ; CODE XREF: dbone_crypt_ins+3Cjlibedog.so:5D695088 1C 30 1B E5 LDR R3, [R11,#DecMode]libedog.so:5D69508C 00 00 53 E3 CMP R3, #0libedog.so:5D695090 06 00 00 1A BNE loc_5D6950B0libedog.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, R2libedog.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_jlibedog.so:5D6950AC 03 00 00 EA B loc_5D6950C0libedog.so:5D6950B0 ; ---------------------------------------------------------------------------libedog.so:5D6950B0libedog.so:5D6950B0 loc_5D6950B0 ; CODE XREF: dbone_crypt_ins+64jlibedog.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, R3libedog.so:5D6950BC 99 F6 FF EB BL putslibedog.so:5D6950C0libedog.so:5D6950C0 loc_5D6950C0 ; CODE XREF: dbone_crypt_ins+58jlibedog.so:5D6950C0 ; dbone_crypt_ins+80jlibedog.so:5D6950C0 14 30 1B E5 LDR R3, [R11,#codedata]libedog.so:5D6950C4 03 00 A0 E1 MOV R0, R3libedog.so:5D6950C8 04 D0 4B E2 SUB SP, R11, #4libedog.so:5D6950CC 00 88 BD E8 LDMFD SP!, {R11,PC}libedog.so:5D6950CC ; End of function dbone_crypt_inslibedog.so:5D6950CClibedog.so:5D6950CC ; -------------//循环解密libedog.so:5D695288 _Z8XorArrayjPhS_j ; CODE XREF: dbone_crypt_file+180plibedog.so:5D695288 ; dbone_crypt_ins+54plibedog.so:5D695288libedog.so:5D695288 codeSize= -0x24libedog.so:5D695288 codedata1= -0x20libedog.so:5D695288 codedata= -0x1Clibedog.so:5D695288 crckey= -0x18libedog.so:5D695288 crckey1= -0x14libedog.so:5D695288 crckeyaddr= -0x10libedog.so:5D695288 crckeyindex= -0xClibedog.so:5D695288 index= -8libedog.so:5D695288libedog.so:5D695288 00 48 2D E9 STMFD SP!, {R11,LR}libedog.so:5D69528C 04 B0 8D E2 ADD R11, SP, #4libedog.so:5D695290 20 D0 4D E2 SUB SP, SP, #0x20libedog.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, #-crckey1libedog.so:5D6952B0 10 30 0B E5 STR R3, [R11,#crckeyaddr]libedog.so:5D6952B4 00 30 A0 E3 MOV R3, #0libedog.so:5D6952B8 08 30 0B E5 STR R3, [R11,#index]libedog.so:5D6952BC 00 30 A0 E3 MOV R3, #0libedog.so:5D6952C0 0C 30 0B E5 STR R3, [R11,#crckeyindex]libedog.so:5D6952C4 00 30 A0 E3 MOV R3, #0libedog.so:5D6952C8 08 30 0B E5 STR R3, [R11,#index]libedog.so:5D6952CC 1E 00 00 EA B loc_5D69534Clibedog.so:5D6952D0 ; ---------------------------------------------------------------------------libedog.so:5D6952D0libedog.so:5D6952D0 loc_5D6952D0 ; CODE XREF: _Z8XorArrayjPhS_j+E0jlibedog.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, R3libedog.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, R2libedog.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, R2libedog.so:5D6952F8 00 20 D2 E5 LDRB R2, [R2]libedog.so:5D6952FC 02 20 21 E0 EOR R2, R1, R2libedog.so:5D695300 FF 20 02 E2 AND R2, R2, #0xFFlibedog.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_5D695334libedog.so:5D695314 14 30 1B E5 LDR R3, [R11,#crckey1]libedog.so:5D695318 03 00 A0 E1 MOV R0, R3libedog.so:5D69531C 6C FF FF EB BL _Z10PolyXorKeyjlibedog.so:5D695320 00 30 A0 E1 MOV R3, R0libedog.so:5D695324 14 30 0B E5 STR R3, [R11,#crckey1]libedog.so:5D695328 00 30 A0 E3 MOV R3, #0libedog.so:5D69532C 0C 30 0B E5 STR R3, [R11,#crckeyindex]libedog.so:5D695330 02 00 00 EA B loc_5D695340libedog.so:5D695334 ; ---------------------------------------------------------------------------libedog.so:5D695334libedog.so:5D695334 loc_5D695334 ; CODE XREF: _Z8XorArrayjPhS_j+88jlibedog.so:5D695334 0C 30 1B E5 LDR R3, [R11,#crckeyindex]libedog.so:5D695338 01 30 83 E2 ADD R3, R3, #1libedog.so:5D69533C 0C 30 0B E5 STR R3, [R11,#crckeyindex]libedog.so:5D695340libedog.so:5D695340 loc_5D695340 ; CODE XREF: _Z8XorArrayjPhS_j+A8jlibedog.so:5D695340 08 30 1B E5 LDR R3, [R11,#index]libedog.so:5D695344 01 30 83 E2 ADD R3, R3, #1libedog.so:5D695348 08 30 0B E5 STR R3, [R11,#index]libedog.so:5D69534Clibedog.so:5D69534C loc_5D69534C ; CODE XREF: _Z8XorArrayjPhS_j+44jlibedog.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, R3libedog.so:5D695358 00 30 A0 D3 MOVLE R3, #0libedog.so:5D69535C 01 30 A0 C3 MOVGT R3, #1libedog.so:5D695360 FF 30 03 E2 AND R3, R3, #0xFFlibedog.so:5D695364 00 00 53 E3 CMP R3, #0libedog.so:5D695368 D8 FF FF 1A BNE loc_5D6952D0libedog.so:5D69536C 04 D0 4B E2 SUB SP, R11, #4libedog.so:5D695370 00 88 BD E8 LDMFD SP!, {R11,PC}libedog.so:5D695370 ; End of function _Z8XorArrayjPhS_jlibedog.so:5D695370libedog.so:5D695374libedog.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, icACC_PRIVATE = 0x00000002, // field, method, icACC_PROTECTED = 0x00000004, // field, method, icACC_STATIC = 0x00000008, // field, method, icACC_FINAL = 0x00000010, // class, field, method, icACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives)ACC_SUPER = 0x00000020, // class (not used in Dalvik)ACC_VOLATILE = 0x00000040, // fieldACC_BRIDGE = 0x00000040, // method (1.5)ACC_TRANSIENT = 0x00000080, // fieldACC_VARARGS = 0x00000080, // method (1.5)ACC_NATIVE = 0x00000100, // methodACC_INTERFACE = 0x00000200, // class, icACC_ABSTRACT = 0x00000400, // class, method, icACC_STRICT = 0x00000800, // methodACC_SYNTHETIC = 0x00001000, // field, method, icACC_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 2struct {u4 classDescriptorHash; // class descriptor hash codeint classDescriptorOffset; // in bytes, from start of DEXint 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;
};#endifvoid fixdexClassData();void initDex(char* DexFileName);
void Uninit();
dexFile.cpp // 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 handleNULL, // default securityPAGE_READWRITE, // read/write permission0, // size of mapping object, highdexsize, // size of mapping object, lowNULL); // name of mapping objectif (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 objectFILE_MAP_ALL_ACCESS, // read/write 0, // high-order 32 // bits of file // offset0, // low-order 32// bits of file // offsetdexsize); // number of bytes// to mapif (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]@1int v5; // [sp+4h] [bp-20h]@1int codedata1; // [sp+8h] [bp-1Ch]@1int *key1; // [sp+10h] [bp-14h]@1int *key2; // [sp+14h] [bp-10h]@1int keyindex; // [sp+18h] [bp-Ch]@1int i; // [sp+1Ch] [bp-8h]@1codedata1 = 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]@1int v5; // [sp+14h] [bp-10h]@1int *v6; // [sp+18h] [bp-Ch]@1int i; // [sp+1Ch] [bp-8h]@1v4 = 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]@1int codelen; // [sp+4h] [bp-18h]@1unsigned __int8 *codedata; // [sp+8h] [bp-14h]@1int DebugInfo; // [sp+Ch] [bp-10h]@1int crc2key; // [sp+14h] [bp-8h]@1DebugInfo = 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文档下载
pdf文档_样本_src_bin.zip
更多推荐
APK加固之类抽取分析与修复
发布评论