APK加固之类抽取分析与修复--纯抽取壳(dvmResolveClass还原)

本文深入剖析APK加固技术,探讨了两种主流加固方法:隐藏DEX文件及修改DEX结构。通过实例展示了加固前后APK结构的变化,并详细分析了壳流程及指令还原算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 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();
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 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文档下载

 pdf文档_样本_src_bin.zip
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值