转载博客链接:http://blog.youkuaiyun.com/qq1084283172/article/details/53557894
周末有空就写下博客了,今天来扯一扯Android平台的脱壳工具DexExtractor。DexExtractor工具的使用比较简单,脱壳的原理也比较简单,工具的作者bunnyrene讲这个android脱壳工具只要是针对bangbang (Bangcle)和ijiami加固的脱壳工具,应该是这两类加固的免费版吧。之前在分析android病毒的时候使用过,但是有时候脱壳还是不成功,需要人工手工脱壳来完成或者说这个工具需要进一步完善一下,不管怎么说谢谢作者大牛。
i.DexExtractor脱壳工具的使用说明和讨论链接
看雪论坛:http://bbs.pediy.com/showthread.php?t=201799
github地址:https://github.com/bunnyblue/DexExtractor
ii.作者编译好的镜像文件system.img的下载地址
网盘地址:http://pan.baidu.com/s/1jG3WQMU
iii.DexExtractor脱壳工具的使用说明截图:
iiii.通过阅读DexExtractor作者提供的使用说明,写下需要注意的地方:
1.DexExtractor脱壳工具的原理是修改了android源码的DexFile.cpp的dexFileParse函数也就是原来的脱壳点函数处进行dexdump的处理,作者提供了Android 4.4---api 19版本系统脱壳的system.img文件(推荐android模拟器用)和libdvm.so文件(android模拟器和android真机都可以使用)。
2.由于DexExtractor工具需要不断的向sdcard写文件,因此特别是android模拟器使用该脱壳工具一定设置Android模拟的sdcard的空间大小。
3.由于DexExtractor工具需要不断的向sdcard写文件,因此被脱壳的apk需要有向sdcard写文件的权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>。
4.DexExtractor工具的system.img文件(Android 4.4.2版本)使用比较简单--直接替换Android 4.4.2版本系统的system.img文件文件即可,Android模拟器的system.img文件的替换比较简单,Android真机的替换可能需要是Android真机进入recovery模式进行替换;DexExtractor工具的libdvm.so文件使用--需要使用abd的push命令将libdvm.so推送到android系统中然后在su权限将libdvm.so文件拷贝或者备份到Android系统的/system/lib/libdvm.so或者Android真机在root的情况下,使用rootexplore.apk(RE管理器工具)将libdvm.so文件拷贝到手机系统的/system/lib/libdvm.so下,替换掉原来Android系统的的/system/lib/libdvm.so文件,并赋予刚才拷贝替换的/system/lib/libdvm.so文件以0775权限然后重启Android真机即可。
- adb push xxx/libdvm.so /data/local/tmp/libdvm.so
- adb shell
- su
- mount -r -w -o remount/system
- mount -o remount,rw /system
- dd if=/system/lib/libdvm.so of=/data/local/tmp/libdvm.bak
- rm /system/lib/libdvm.so
- cat /data/local/tmp/libdvm.so >/system/lib/libdvm.so
- chmod 0775 /system/lib/libdvm.so
- mount -o remount,ro /system
- exit
- exit
- adb reboot
adb push xxx/libdvm.so /data/local/tmp/libdvm.so
adb shell
su
mount -r -w -o remount/system
mount -o remount,rw /system
dd if=/system/lib/libdvm.so of=/data/local/tmp/libdvm.bak
rm /system/lib/libdvm.so
cat /data/local/tmp/libdvm.so >/system/lib/libdvm.so
chmod 0775 /system/lib/libdvm.so
mount -o remount,ro /system
exit
exit
adb reboot
使用前提条件:
1.如果是android模拟器使用脱壳镜像文件system.img,一定要配置sdcard参数
2.需要脱壳的apk如果没有写权限,需要添加上写sdcard的权限。
如:
apk没有写权限的反编译了加上write权限
说明:
< !--往sdcard写入数据权限 -->
< uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
< !--sdcard创建/删除文件权限 -->
< uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
需要使用的权限:
< uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
#如果脱壳apk没有文件的写权限,反编译以后加上sdcard文件的写权限,然后重新打包apk程序。
DexExtractor脱壳实例(使用Android模拟器):
1.找到Android 4.4.2对应的API 19的系统文件的目录,如下:
E:\BaiduYunDownload\adt-bundle-windows-x86_64-20140702\sdk\system-images\android-19\default\armeabi-v7a
备份原来的system.img文件,然后将修改的system.img文件解压后拷贝到这个目录里。
2.在android模拟器上创建API为19的android模拟器,千万不能忘了为模拟器添加sdcard的内存空间参数。
3.用反编译工具查看被脱壳的apk是否有-----写文件的权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>没有就添加上写文件的权限并重新打包apk程序。
4.adb install xxx.apk 安装需要脱壳的apk程序到上面创建的android模拟器上。
5.打开logcat的logcat 监视log "被加固的包名" 和 "dvmtag" ,当看到 "create file end",说明脱壳成功;从eclipse中导出log日志文件并保存。(这里请参考作者提供的脱壳成功的说明)
6.adb pull /sdcard/classes_xxx.dex 从android模拟器的sdcard中导出脱壳后但是经过base64加密的dex文件。
示例:
adb pull /sdcard/tx.qq898507339.bzy9_classes_5528.dex
7.脱壳后的dex文件被Base64编码了,需要解码。
解码dex文件:
Java -jar Decoder.jar dex目录
java -jar Decoder.jar xxxx\tx.qq898507339.bzy9_classes_5528.dex
======================================================================================================
java环境的正确配置
安装JDK,比如目录在C:\Java
为了方便java程序的开发,需要配置一下环境变量,右击我的电脑->属性->高级->环境变量->用户变量中单击[新建(N)]添加以下环境变量
(假定你的JDK安装路径为C:\Java\jdk1.6.0_30)
JAVA_HOME
C:\Java\jdk1.6.0_30
PATH
C:\Java\jdk1.6.0_30\bin
CLASSPATH
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(注前面的点号和分号一定不能丢,还有中间的,后面的分号也不要丢了)
说明:CLASSPATH可以再增加一些第三方的jar文件,方便手工编译和运行程序。
======================================================================================================
但是呢,由于一些加固如梆梆加固,会对dex的内存dump脱壳进行检测,具体的就是hook修改当前进程的read、write读写相关的函数,一旦检测到read、write读写相关的函数的操作中有对dex文件的dump行为会有对抗的处理,防止dex的内存dump,因此呢,DexExtractor脱壳工具的作者为了过掉这种内存dump的对抗,需要先将原始的dex文件数据进行base64加密然后进行写文件到sdcard中进行输出,当pull导出拿到base64加密的dex文件时还需要进行base64的解密才能获取到原始的dex文件,具体的脱壳功能见DexHacker.cpp文件。
- //
- // DexHacker.cpp
- //
- //
- // Created by BunnyBlue on 6/23/15.
- //
- //
- #include "DexHacker.h"
- void DexHacker::writeDex2Encoded(unsigned char *data, size_t length){
- #ifdef CODE_DVM
- ALOGE("--pacthed-- inject .dex length %d flag=%d",length,flags);
- char dexbuffer[64]={0};
- char dexbufferNamed[128]={0};
- char bufferProcess[256]={0};
- // 获取当前进程的名称字符串
- bufferProcess= getProcessName(bufferProcess);
- sprintf(dexbuffer, "classes_%d", length);
- strcat(dexbufferNamed,"/sdcard/");
- if (bufferProcess!=NULL) {
- strcat(dexbufferNamed, bufferProcess);
- strcat(dexbufferNamed, dexbuffer);
- }else{
- ALOGE("--pacthed-- , FAULT pid not found\n");
- return;
- }
- // strcat(dexbufferNamed,dexbuffer);
- strcat(dexbufferNamed,".dex");
- ALOGE("--pacthed-- , %s\n", dexbufferNamed);
- ALOGE("--pacthed-- debug dalvikParse find dex try write file ");
- // 删除原来存在的文件
- int status = remove(dexbufferNamed);
- if( status == 0 )
- ALOGE("%s file deleted successfully.\n",dexbufferNamed);
- else
- {
- ALOGE("Unable to delete the file\n");
- }
- // 申请内存缓冲区备份信息
- u1* buffer_data_dest=(u1*)malloc((length+1)*sizeof(u1));
- // 拷贝内存中的dex文件的数据到内存缓冲区buffer_data_dest中备份
- memcpy(buffer_data_dest, data, length);
- // 创建文件
- FILE *fp = fopen(dexbufferNamed,"wb");
- if(NULL==fp) {
- ALOGE("--pacthed-- , can't create file ! maybe you need mount sdcard again!");
- ALOGE( "%s data %s\n", strerror(errno),data);
- } else {
- ALOGE("--pacthed-- create file %s ",dexbufferNamed);
- int dex_lem_local = length>2048? 1024:length;
- // 申请内存空间保存base64加密后的dex文件的数据
- unsigned char *dst=(unsigned char*)malloc(length*2.5);
- unsigned long dlen=length*2.5;
- // 将原始的dex文件的数据进行base64加密
- base64_encode(dst, &dlen, data, length);
- // 将base64加密后的dex文件的数据进行写文件输出到sdcard中
- fwrite(dst, dlen, 1, fp);
- //fwrite(data, sizeof(u1), length, fp);
- ALOGE("--pacthed-- create file end ");
- //fflush(fp);
- fclose(fp);
- fp = NULL;
- }
- free(buffer_data_dest);
- #else
- char dexbuffer[64]={0};
- char dexbufferNamed[128]={0};
- sprintf(dexbuffer, "classes_%d", length);
- //strcat(dexbufferNamed,");
- strcat(dexbufferNamed,dexbuffer);
- strcat(dexbufferNamed,".dex");
- int status = remove(dexbufferNamed);
- FILE *fp = fopen(dexbufferNamed,"wb");
- if(NULL==fp){
- } else {
- unsigned char *dst=(unsigned char*)malloc(length*2.5);
- unsigned long dlen=length*2.5;
- base64_encode(dst, &dlen, data, length);
- fwrite(dst, dlen, 1, fp);
- //fflush(fp);
- fclose(fp);
- fp = NULL;
- }
- #endif
- }
- void DexHacker::writeEncodedDex2Dex(const char *encodedDex){
- FILE *srcDexFile=fopen(encodedDex,"rb");
- std::string outDexFile(encodedDex);
- outDexFile.append(".read.dex");
- FILE *outFile=fopen(outDexFile.c_str(), "wb");
- if (srcDexFile!=NULL) {
- fseek(srcDexFile,0,SEEK_END);
- long fsize =ftell(srcDexFile);
- rewind(srcDexFile);
- std::cout<<sizeof(char)<<"\nxxxxxxxx"<<fsize;
- unsigned char *list=(unsigned char*)malloc(sizeof(char)*fsize);
- unsigned long numread =fread(list,sizeof(char),fsize,srcDexFile);
- // blue_dump_data(list, (unsigned long )fsize);
- unsigned char *dst=(unsigned char*)malloc(numread);
- unsigned long dlen=numread;
- base64_decode(dst, &dlen, list, numread);
- fclose(srcDexFile);
- int ret=fwrite(dst, 1, dlen, outFile);
- fclose(outFile);
- // std::cout<<"\n"<<repeate<<"numread"<<numread;
- }
- }
- char* itoa(int i, char b[]){
- char const digit[] = "0123456789";
- char* p = b;
- if(i<0){
- *p++ = '-';
- i *= -1;
- }
- int shifter = i;
- do{ //Move to where representation ends
- ++p;
- shifter = shifter/10;
- }while(shifter);
- *p = '\0';
- do{ //Move back, inserting digits as u go
- *--p = digit[i%10];
- i = i/10;
- }while(i);
- return b;
- }
- // 获取当前进程的名称
- char * DexHacker::getProcessName(char * buffer){
- char path_t[256]={0};
- // char buffer[512]={0} ;
- // 获取当前进程的pid
- pid_t pid=getpid();
- char str[15];
- sprintf(str, "%d", pid);
- memset(path_t, 0 , sizeof(path_t));
- strcat(path_t, "/proc/");
- strcat(path_t, str);
- strcat(path_t, "/cmdline");
- //LOG_ERROR("zhw", "path:%s", path_t);
- int fd_t = open(path_t, O_RDONLY);
- if(fd_t>0){
- int read_count = read(fd_t, buffer, BUFLEN);
- if(read_count>0){
- return buffer;
- }
- }
- return NULL;
- }
//
// DexHacker.cpp
//
//
// Created by BunnyBlue on 6/23/15.
//
//
#include "DexHacker.h"
void DexHacker::writeDex2Encoded(unsigned char *data, size_t length){
#ifdef CODE_DVM
ALOGE("--pacthed-- inject .dex length %d flag=%d",length,flags);
char dexbuffer[64]={0};
char dexbufferNamed[128]={0};
char bufferProcess[256]={0};
// 获取当前进程的名称字符串
bufferProcess= getProcessName(bufferProcess);
sprintf(dexbuffer, "classes_%d", length);
strcat(dexbufferNamed,"/sdcard/");
if (bufferProcess!=NULL) {
strcat(dexbufferNamed, bufferProcess);
strcat(dexbufferNamed, dexbuffer);
}else{
ALOGE("--pacthed-- , FAULT pid not found\n");
return;
}
// strcat(dexbufferNamed,dexbuffer);
strcat(dexbufferNamed,".dex");
ALOGE("--pacthed-- , %s\n", dexbufferNamed);
ALOGE("--pacthed-- debug dalvikParse find dex try write file ");
// 删除原来存在的文件
int status = remove(dexbufferNamed);
if( status == 0 )
ALOGE("%s file deleted successfully.\n",dexbufferNamed);
else
{
ALOGE("Unable to delete the file\n");
}
// 申请内存缓冲区备份信息
u1* buffer_data_dest=(u1*)malloc((length+1)*sizeof(u1));
// 拷贝内存中的dex文件的数据到内存缓冲区buffer_data_dest中备份
memcpy(buffer_data_dest, data, length);
// 创建文件
FILE *fp = fopen(dexbufferNamed,"wb");
if(NULL==fp) {
ALOGE("--pacthed-- , can't create file ! maybe you need mount sdcard again!");
ALOGE( "%s data %s\n", strerror(errno),data);
} else {
ALOGE("--pacthed-- create file %s ",dexbufferNamed);
int dex_lem_local = length>2048? 1024:length;
// 申请内存空间保存base64加密后的dex文件的数据
unsigned char *dst=(unsigned char*)malloc(length*2.5);
unsigned long dlen=length*2.5;
// 将原始的dex文件的数据进行base64加密
base64_encode(dst, &dlen, data, length);
// 将base64加密后的dex文件的数据进行写文件输出到sdcard中
fwrite(dst, dlen, 1, fp);
//fwrite(data, sizeof(u1), length, fp);
ALOGE("--pacthed-- create file end ");
//fflush(fp);
fclose(fp);
fp = NULL;
}
free(buffer_data_dest);
#else
char dexbuffer[64]={0};
char dexbufferNamed[128]={0};
sprintf(dexbuffer, "classes_%d", length);
//strcat(dexbufferNamed,");
strcat(dexbufferNamed,dexbuffer);
strcat(dexbufferNamed,".dex");
int status = remove(dexbufferNamed);
FILE *fp = fopen(dexbufferNamed,"wb");
if(NULL==fp){
} else {
unsigned char *dst=(unsigned char*)malloc(length*2.5);
unsigned long dlen=length*2.5;
base64_encode(dst, &dlen, data, length);
fwrite(dst, dlen, 1, fp);
//fflush(fp);
fclose(fp);
fp = NULL;
}
#endif
}
void DexHacker::writeEncodedDex2Dex(const char *encodedDex){
FILE *srcDexFile=fopen(encodedDex,"rb");
std::string outDexFile(encodedDex);
outDexFile.append(".read.dex");
FILE *outFile=fopen(outDexFile.c_str(), "wb");
if (srcDexFile!=NULL) {
fseek(srcDexFile,0,SEEK_END);
long fsize =ftell(srcDexFile);
rewind(srcDexFile);
std::cout<<sizeof(char)<<"\nxxxxxxxx"<<fsize;
unsigned char *list=(unsigned char*)malloc(sizeof(char)*fsize);
unsigned long numread =fread(list,sizeof(char),fsize,srcDexFile);
// blue_dump_data(list, (unsigned long )fsize);
unsigned char *dst=(unsigned char*)malloc(numread);
unsigned long dlen=numread;
base64_decode(dst, &dlen, list, numread);
fclose(srcDexFile);
int ret=fwrite(dst, 1, dlen, outFile);
fclose(outFile);
// std::cout<<"\n"<<repeate<<"numread"<<numread;
}
}
char* itoa(int i, char b[]){
char const digit[] = "0123456789";
char* p = b;
if(i<0){
*p++ = '-';
i *= -1;
}
int shifter = i;
do{ //Move to where representation ends
++p;
shifter = shifter/10;
}while(shifter);
*p = '\0';
do{ //Move back, inserting digits as u go
*--p = digit[i%10];
i = i/10;
}while(i);
return b;
}
// 获取当前进程的名称
char * DexHacker::getProcessName(char * buffer){
char path_t[256]={0};
// char buffer[512]={0} ;
// 获取当前进程的pid
pid_t pid=getpid();
char str[15];
sprintf(str, "%d", pid);
memset(path_t, 0 , sizeof(path_t));
strcat(path_t, "/proc/");
strcat(path_t, str);
strcat(path_t, "/cmdline");
//LOG_ERROR("zhw", "path:%s", path_t);
int fd_t = open(path_t, O_RDONLY);
if(fd_t>0){
int read_count = read(fd_t, buffer, BUFLEN);
if(read_count>0){
return buffer;
}
}
return NULL;
}
关于DexExtractor脱壳工具的自行修改和扩展:根据自己的脱壳思路,编写额外的脱壳代码文件,添加自选Android系统版本的DexFile.cpp文件并将额外的脱壳代码文件添加到编译配置文件Android.mk中,然后在DexFile.cpp文件路径下进行android源码的局部模块的编译,具体编译参考见http://blog.youkuaiyun.com/qq1084283172/article/details/53365659。
iiiiii.DexExtractor脱壳工具的其他代码文件:
- /*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * Access the contents of a .dex file.
- */
- #include "DexFile.h"
- #include "DexOptData.h"
- #include "DexProto.h"
- #include "DexCatch.h"
- #include "Leb128.h"
- #include "sha1.h"
- #include "ZipArchive.h"
- #include <zlib.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <string.h>
- #include <fcntl.h>
- #include <errno.h>
- #include "DexHacker.cpp"
- /*
- * Verifying checksums is good, but it slows things down and causes us to
- * touch every page. In the "optimized" world, it doesn't work at all,
- * because we rewrite the contents.
- */
- static const bool kVerifyChecksum = false;
- static const bool kVerifySignature = false;
- /* (documented in header) */
- char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
- const char* string = dexGetPrimitiveTypeDescriptor(type);
- return (string == NULL) ? '\0' : string[0];
- }
- /* (documented in header) */
- const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
- switch (type) {
- case PRIM_VOID: return "V";
- case PRIM_BOOLEAN: return "Z";
- case PRIM_BYTE: return "B";
- case PRIM_SHORT: return "S";
- case PRIM_CHAR: return "C";
- case PRIM_INT: return "I";
- case PRIM_LONG: return "J";
- case PRIM_FLOAT: return "F";
- case PRIM_DOUBLE: return "D";
- default: return NULL;
- }
- return NULL;
- }
- /* (documented in header) */
- const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
- switch (type) {
- case PRIM_VOID: return NULL;
- case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
- case PRIM_BYTE: return "Ljava/lang/Byte;";
- case PRIM_SHORT: return "Ljava/lang/Short;";
- case PRIM_CHAR: return "Ljava/lang/Character;";
- case PRIM_INT: return "Ljava/lang/Integer;";
- case PRIM_LONG: return "Ljava/lang/Long;";
- case PRIM_FLOAT: return "Ljava/lang/Float;";
- case PRIM_DOUBLE: return "Ljava/lang/Double;";
- default: return NULL;
- }
- }
- /* (documented in header) */
- PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
- switch (descriptorChar) {
- case 'V': return PRIM_VOID;
- case 'Z': return PRIM_BOOLEAN;
- case 'B': return PRIM_BYTE;
- case 'S': return PRIM_SHORT;
- case 'C': return PRIM_CHAR;
- case 'I': return PRIM_INT;
- case 'J': return PRIM_LONG;
- case 'F': return PRIM_FLOAT;
- case 'D': return PRIM_DOUBLE;
- default: return PRIM_NOT;
- }
- }
- /* Return the UTF-8 encoded string with the specified string_id index,
- * also filling in the UTF-16 size (number of 16-bit code points).*/
- const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
- u4* utf16Size) {
- const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
- const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
- *utf16Size = readUnsignedLeb128(&ptr);
- return (const char*) ptr;
- }
- /*
- * Format an SHA-1 digest for printing. tmpBuf must be able to hold at
- * least kSHA1DigestOutputLen bytes.
- */
- const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf);
- /*
- * Compute a SHA-1 digest on a range of bytes.
- */
- static void dexComputeSHA1Digest(const unsigned char* data, size_t length,
- unsigned char digest[])
- {
- SHA1_CTX context;
- SHA1Init(&context);
- SHA1Update(&context, data, length);
- SHA1Final(digest, &context);
- }
- /*
- * Format the SHA-1 digest into the buffer, which must be able to hold at
- * least kSHA1DigestOutputLen bytes. Returns a pointer to the buffer,
- */
- static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf)
- {
- static const char hexDigit[] = "0123456789abcdef";
- char* cp;
- int i;
- cp = tmpBuf;
- for (i = 0; i < kSHA1DigestLen; i++) {
- *cp++ = hexDigit[digest[i] >> 4];
- *cp++ = hexDigit[digest[i] & 0x0f];
- }
- *cp++ = '\0';
- assert(cp == tmpBuf + kSHA1DigestOutputLen);
- return tmpBuf;
- }
- /*
- * Compute a hash code on a UTF-8 string, for use with internal hash tables.
- *
- * This may or may not be compatible with UTF-8 hash functions used inside
- * the Dalvik VM.
- *
- * The basic "multiply by 31 and add" approach does better on class names
- * than most other things tried (e.g. adler32).
- */
- static u4 classDescriptorHash(const char* str)
- {
- u4 hash = 1;
- while (*str != '\0')
- hash = hash * 31 + *str++;
- return hash;
- }
- /*
- * Add an entry to the class lookup table. We hash the string and probe
- * until we find an open slot.
- */
- static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup,
- int stringOff, int classDefOff, int* pNumProbes)
- {
- const char* classDescriptor =
- (const char*) (pDexFile->baseAddr + stringOff);
- const DexClassDef* pClassDef =
- (const DexClassDef*) (pDexFile->baseAddr + classDefOff);
- u4 hash = classDescriptorHash(classDescriptor);
- int mask = pLookup->numEntries-1;
- int idx = hash & mask;
- /*
- * Find the first empty slot. We oversized the table, so this is
- * guaranteed to finish.
- */
- int probes = 0;
- while (pLookup->table[idx].classDescriptorOffset != 0) {
- idx = (idx + 1) & mask;
- probes++;
- }
- //if (probes > 1)
- // ALOGW("classLookupAdd: probes=%d", probes);
- pLookup->table[idx].classDescriptorHash = hash;
- pLookup->table[idx].classDescriptorOffset = stringOff;
- pLookup->table[idx].classDefOffset = classDefOff;
- *pNumProbes = probes;
- }
- /*
- * Create the class lookup hash table.
- *
- * Returns newly-allocated storage.
- */
- DexClassLookup* dexCreateClassLookup(DexFile* pDexFile)
- {
- DexClassLookup* pLookup;
- int allocSize;
- int i, numEntries;
- int numProbes, totalProbes, maxProbes;
- numProbes = totalProbes = maxProbes = 0;
- assert(pDexFile != NULL);
- /*
- * Using a factor of 3 results in far less probing than a factor of 2,
- * but almost doubles the flash storage requirements for the bootstrap
- * DEX files. The overall impact on class loading performance seems
- * to be minor. We could probably get some performance improvement by
- * using a secondary hash.
- */
- numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2);
- allocSize = offsetof(DexClassLookup, table)
- + numEntries * sizeof(pLookup->table[0]);
- pLookup = (DexClassLookup*) calloc(1, allocSize);
- if (pLookup == NULL)
- return NULL;
- pLookup->size = allocSize;
- pLookup->numEntries = numEntries;
- for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) {
- const DexClassDef* pClassDef;
- const char* pString;
- pClassDef = dexGetClassDef(pDexFile, i);
- pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
- classLookupAdd(pDexFile, pLookup,
- (u1*)pString - pDexFile->baseAddr,
- (u1*)pClassDef - pDexFile->baseAddr, &numProbes);
- if (numProbes > maxProbes)
- maxProbes = numProbes;
- totalProbes += numProbes;
- }
- ALOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d"
- " total=%d max=%d",
- pDexFile->pHeader->classDefsSize, numEntries,
- (100 * pDexFile->pHeader->classDefsSize) / numEntries,
- allocSize, totalProbes, maxProbes);
- return pLookup;
- }
- /*
- * Set up the basic raw data pointers of a DexFile. This function isn't
- * meant for general use.
- */
- void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
- DexHeader *pHeader = (DexHeader*) data;
- pDexFile->baseAddr = data;
- pDexFile->pHeader = pHeader;
- pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
- pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
- pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
- pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
- pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
- pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
- pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
- }
- /*
- * Parse an optimized or unoptimized .dex file sitting in memory. This is
- * called after the byte-ordering and structure alignment has been fixed up.
- *
- * On success, return a newly-allocated DexFile.
- */
- DexFile* dexFileParse(const u1* data, size_t length, int flags)
- {
- //******************************添加的脱壳代码**************************
- // 构建脱壳工具实例
- DexHacker mDexHacker;
- // 从内存dump dex文件
- mDexHacker.writeDex2Encoded(data,(unsigned int)length);
- //******************************常规手动脱壳点**************************
- DexFile* pDexFile = NULL;
- const DexHeader* pHeader;
- const u1* magic;
- int result = -1;
- if (length < sizeof(DexHeader)) {
- ALOGE("too short to be a valid .dex");
- goto bail; /* bad file format */
- }
- pDexFile = (DexFile*) malloc(sizeof(DexFile));
- if (pDexFile == NULL)
- goto bail; /* alloc failure */
- memset(pDexFile, 0, sizeof(DexFile));
- /*
- * Peel off the optimized header.
- */
- if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
- magic = data;
- if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
- ALOGE("bad opt version (0x%02x %02x %02x %02x)",
- magic[4], magic[5], magic[6], magic[7]);
- goto bail;
- }
- pDexFile->pOptHeader = (const DexOptHeader*) data;
- ALOGV("Good opt header, DEX offset is %d, flags=0x%02x",
- pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
- /* parse the optimized dex file tables */
- if (!dexParseOptData(data, length, pDexFile))
- goto bail;
- /* ignore the opt header and appended data from here on out */
- data += pDexFile->pOptHeader->dexOffset;
- length -= pDexFile->pOptHeader->dexOffset;
- if (pDexFile->pOptHeader->dexLength > length) {
- ALOGE("File truncated? stored len=%d, rem len=%d",
- pDexFile->pOptHeader->dexLength, (int) length);
- goto bail;
- }
- length = pDexFile->pOptHeader->dexLength;
- }
- dexFileSetupBasicPointers(pDexFile, data);
- pHeader = pDexFile->pHeader;
- if (!dexHasValidMagic(pHeader)) {
- goto bail;
- }
- /*
- * Verify the checksum(s). This is reasonably quick, but does require
- * touching every byte in the DEX file. The base checksum changes after
- * byte-swapping and DEX optimization.
- */
- if (flags & kDexParseVerifyChecksum) {
- u4 adler = dexComputeChecksum(pHeader);
- if (adler != pHeader->checksum) {
- ALOGE("ERROR: bad checksum (%08x vs %08x)",
- adler, pHeader->checksum);
- if (!(flags & kDexParseContinueOnError))
- goto bail;
- } else {
- ALOGV("+++ adler32 checksum (%08x) verified", adler);
- }
- const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
- if (pOptHeader != NULL) {
- adler = dexComputeOptChecksum(pOptHeader);
- if (adler != pOptHeader->checksum) {
- ALOGE("ERROR: bad opt checksum (%08x vs %08x)",
- adler, pOptHeader->checksum);
- if (!(flags & kDexParseContinueOnError))
- goto bail;
- } else {
- ALOGV("+++ adler32 opt checksum (%08x) verified", adler);
- }
- }
- }
- /*
- * Verify the SHA-1 digest. (Normally we don't want to do this --
- * the digest is used to uniquely identify the original DEX file, and
- * can't be computed for verification after the DEX is byte-swapped
- * and optimized.)
- */
- if (kVerifySignature) {
- unsigned char sha1Digest[kSHA1DigestLen];
- const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) +
- kSHA1DigestLen;
- dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest);
- if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) {
- char tmpBuf1[kSHA1DigestOutputLen];
- char tmpBuf2[kSHA1DigestOutputLen];
- ALOGE("ERROR: bad SHA1 digest (%s vs %s)",
- dexSHA1DigestToStr(sha1Digest, tmpBuf1),
- dexSHA1DigestToStr(pHeader->signature, tmpBuf2));
- if (!(flags & kDexParseContinueOnError))
- goto bail;
- } else {
- ALOGV("+++ sha1 digest verified");
- }
- }
- if (pHeader->fileSize != length) {
- ALOGE("ERROR: stored file size (%d) != expected (%d)",
- (int) pHeader->fileSize, (int) length);
- if (!(flags & kDexParseContinueOnError))
- goto bail;
- }
- if (pHeader->classDefsSize == 0) {
- ALOGE("ERROR: DEX file has no classes in it, failing");
- goto bail;
- }
- /*
- * Success!
- */
- result = 0;
- bail:
- if (result != 0 && pDexFile != NULL) {
- dexFileFree(pDexFile);
- pDexFile = NULL;
- }
- return pDexFile;
- }
- /*
- * Free up the DexFile and any associated data structures.
- *
- * Note we may be called with a partially-initialized DexFile.
- */
- void dexFileFree(DexFile* pDexFile)
- {
- if (pDexFile == NULL)
- return;
- free(pDexFile);
- }
- /*
- * Look up a class definition entry by descriptor.
- *
- * "descriptor" should look like "Landroid/debug/Stuff;".
- */
- const DexClassDef* dexFindClass(const DexFile* pDexFile,
- const char* descriptor)
- {
- const DexClassLookup* pLookup = pDexFile->pClassLookup;
- u4 hash;
- int idx, mask;
- hash = classDescriptorHash(descriptor);
- mask = pLookup->numEntries - 1;
- idx = hash & mask;
- /*
- * Search until we find a matching entry or an empty slot.
- */
- while (true) {
- int offset;
- offset = pLookup->table[idx].classDescriptorOffset;
- if (offset == 0)
- return NULL;
- if (pLookup->table[idx].classDescriptorHash == hash) {
- const char* str;
- str = (const char*) (pDexFile->baseAddr + offset);
- if (strcmp(str, descriptor) == 0) {
- return (const DexClassDef*)
- (pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
- }
- }
- idx = (idx + 1) & mask;
- }
- }
- /*
- * Compute the DEX file checksum for a memory-mapped DEX file.
- */
- u4 dexComputeChecksum(const DexHeader* pHeader)
- {
- const u1* start = (const u1*) pHeader;
- uLong adler = adler32(0L, Z_NULL, 0);
- const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
- return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum);
- }
- /*
- * Compute the size, in bytes, of a DexCode.
- */
- size_t dexGetDexCodeSize(const DexCode* pCode)
- {
- /*
- * The catch handler data is the last entry. It has a variable number
- * of variable-size pieces, so we need to create an iterator.
- */
- u4 handlersSize;
- u4 offset;
- u4 ui;
- if (pCode->triesSize != 0) {
- handlersSize = dexGetHandlersSize(pCode);
- offset = dexGetFirstHandlerOffset(pCode);
- } else {
- handlersSize = 0;
- offset = 0;
- }
- for (ui = 0; ui < handlersSize; ui++) {
- DexCatchIterator iterator;
- dexCatchIteratorInit(&iterator, pCode, offset);
- offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
- }
- const u1* handlerData = dexGetCatchHandlerData(pCode);
- //ALOGD("+++ pCode=%p handlerData=%p last offset=%d",
- // pCode, handlerData, offset);
- /* return the size of the catch handler + everything before it */
- return (handlerData - (u1*) pCode) + offset;
- }
- /*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
- u4 dexRoundUpPower2(u4 val)
- {
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val++;
- return val;
- }
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Access the contents of a .dex file.
*/
#include "DexFile.h"
#include "DexOptData.h"
#include "DexProto.h"
#include "DexCatch.h"
#include "Leb128.h"
#include "sha1.h"
#include "ZipArchive.h"
#include <zlib.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "DexHacker.cpp"
/*
* Verifying checksums is good, but it slows things down and causes us to
* touch every page. In the "optimized" world, it doesn't work at all,
* because we rewrite the contents.
*/
static const bool kVerifyChecksum = false;
static const bool kVerifySignature = false;
/* (documented in header) */
char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
const char* string = dexGetPrimitiveTypeDescriptor(type);
return (string == NULL) ? '\0' : string[0];
}
/* (documented in header) */
const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
switch (type) {
case PRIM_VOID: return "V";
case PRIM_BOOLEAN: return "Z";
case PRIM_BYTE: return "B";
case PRIM_SHORT: return "S";
case PRIM_CHAR: return "C";
case PRIM_INT: return "I";
case PRIM_LONG: return "J";
case PRIM_FLOAT: return "F";
case PRIM_DOUBLE: return "D";
default: return NULL;
}
return NULL;
}
/* (documented in header) */
const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
switch (type) {
case PRIM_VOID: return NULL;
case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
case PRIM_BYTE: return "Ljava/lang/Byte;";
case PRIM_SHORT: return "Ljava/lang/Short;";
case PRIM_CHAR: return "Ljava/lang/Character;";
case PRIM_INT: return "Ljava/lang/Integer;";
case PRIM_LONG: return "Ljava/lang/Long;";
case PRIM_FLOAT: return "Ljava/lang/Float;";
case PRIM_DOUBLE: return "Ljava/lang/Double;";
default: return NULL;
}
}
/* (documented in header) */
PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
switch (descriptorChar) {
case 'V': return PRIM_VOID;
case 'Z': return PRIM_BOOLEAN;
case 'B': return PRIM_BYTE;
case 'S': return PRIM_SHORT;
case 'C': return PRIM_CHAR;
case 'I': return PRIM_INT;
case 'J': return PRIM_LONG;
case 'F': return PRIM_FLOAT;
case 'D': return PRIM_DOUBLE;
default: return PRIM_NOT;
}
}
/* Return the UTF-8 encoded string with the specified string_id index,
* also filling in the UTF-16 size (number of 16-bit code points).*/
const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
u4* utf16Size) {
const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
*utf16Size = readUnsignedLeb128(&ptr);
return (const char*) ptr;
}
/*
* Format an SHA-1 digest for printing. tmpBuf must be able to hold at
* least kSHA1DigestOutputLen bytes.
*/
const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf);
/*
* Compute a SHA-1 digest on a range of bytes.
*/
static void dexComputeSHA1Digest(const unsigned char* data, size_t length,
unsigned char digest[])
{
SHA1_CTX context;
SHA1Init(&context);
SHA1Update(&context, data, length);
SHA1Final(digest, &context);
}
/*
* Format the SHA-1 digest into the buffer, which must be able to hold at
* least kSHA1DigestOutputLen bytes. Returns a pointer to the buffer,
*/
static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf)
{
static const char hexDigit[] = "0123456789abcdef";
char* cp;
int i;
cp = tmpBuf;
for (i = 0; i < kSHA1DigestLen; i++) {
*cp++ = hexDigit[digest[i] >> 4];
*cp++ = hexDigit[digest[i] & 0x0f];
}
*cp++ = '\0';
assert(cp == tmpBuf + kSHA1DigestOutputLen);
return tmpBuf;
}
/*
* Compute a hash code on a UTF-8 string, for use with internal hash tables.
*
* This may or may not be compatible with UTF-8 hash functions used inside
* the Dalvik VM.
*
* The basic "multiply by 31 and add" approach does better on class names
* than most other things tried (e.g. adler32).
*/
static u4 classDescriptorHash(const char* str)
{
u4 hash = 1;
while (*str != '\0')
hash = hash * 31 + *str++;
return hash;
}
/*
* Add an entry to the class lookup table. We hash the string and probe
* until we find an open slot.
*/
static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup,
int stringOff, int classDefOff, int* pNumProbes)
{
const char* classDescriptor =
(const char*) (pDexFile->baseAddr + stringOff);
const DexClassDef* pClassDef =
(const DexClassDef*) (pDexFile->baseAddr + classDefOff);
u4 hash = classDescriptorHash(classDescriptor);
int mask = pLookup->numEntries-1;
int idx = hash & mask;
/*
* Find the first empty slot. We oversized the table, so this is
* guaranteed to finish.
*/
int probes = 0;
while (pLookup->table[idx].classDescriptorOffset != 0) {
idx = (idx + 1) & mask;
probes++;
}
//if (probes > 1)
// ALOGW("classLookupAdd: probes=%d", probes);
pLookup->table[idx].classDescriptorHash = hash;
pLookup->table[idx].classDescriptorOffset = stringOff;
pLookup->table[idx].classDefOffset = classDefOff;
*pNumProbes = probes;
}
/*
* Create the class lookup hash table.
*
* Returns newly-allocated storage.
*/
DexClassLookup* dexCreateClassLookup(DexFile* pDexFile)
{
DexClassLookup* pLookup;
int allocSize;
int i, numEntries;
int numProbes, totalProbes, maxProbes;
numProbes = totalProbes = maxProbes = 0;
assert(pDexFile != NULL);
/*
* Using a factor of 3 results in far less probing than a factor of 2,
* but almost doubles the flash storage requirements for the bootstrap
* DEX files. The overall impact on class loading performance seems
* to be minor. We could probably get some performance improvement by
* using a secondary hash.
*/
numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2);
allocSize = offsetof(DexClassLookup, table)
+ numEntries * sizeof(pLookup->table[0]);
pLookup = (DexClassLookup*) calloc(1, allocSize);
if (pLookup == NULL)
return NULL;
pLookup->size = allocSize;
pLookup->numEntries = numEntries;
for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) {
const DexClassDef* pClassDef;
const char* pString;
pClassDef = dexGetClassDef(pDexFile, i);
pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
classLookupAdd(pDexFile, pLookup,
(u1*)pString - pDexFile->baseAddr,
(u1*)pClassDef - pDexFile->baseAddr, &numProbes);
if (numProbes > maxProbes)
maxProbes = numProbes;
totalProbes += numProbes;
}
ALOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d"
" total=%d max=%d",
pDexFile->pHeader->classDefsSize, numEntries,
(100 * pDexFile->pHeader->classDefsSize) / numEntries,
allocSize, totalProbes, maxProbes);
return pLookup;
}
/*
* Set up the basic raw data pointers of a DexFile. This function isn't
* meant for general use.
*/
void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
DexHeader *pHeader = (DexHeader*) data;
pDexFile->baseAddr = data;
pDexFile->pHeader = pHeader;
pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
}
/*
* Parse an optimized or unoptimized .dex file sitting in memory. This is
* called after the byte-ordering and structure alignment has been fixed up.
*
* On success, return a newly-allocated DexFile.
*/
DexFile* dexFileParse(const u1* data, size_t length, int flags)
{
//******************************添加的脱壳代码**************************
// 构建脱壳工具实例
DexHacker mDexHacker;
// 从内存dump dex文件
mDexHacker.writeDex2Encoded(data,(unsigned int)length);
//******************************常规手动脱壳点**************************
DexFile* pDexFile = NULL;
const DexHeader* pHeader;
const u1* magic;
int result = -1;
if (length < sizeof(DexHeader)) {
ALOGE("too short to be a valid .dex");
goto bail; /* bad file format */
}
pDexFile = (DexFile*) malloc(sizeof(DexFile));
if (pDexFile == NULL)
goto bail; /* alloc failure */
memset(pDexFile, 0, sizeof(DexFile));
/*
* Peel off the optimized header.
*/
if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
magic = data;
if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
ALOGE("bad opt version (0x%02x %02x %02x %02x)",
magic[4], magic[5], magic[6], magic[7]);
goto bail;
}
pDexFile->pOptHeader = (const DexOptHeader*) data;
ALOGV("Good opt header, DEX offset is %d, flags=0x%02x",
pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
/* parse the optimized dex file tables */
if (!dexParseOptData(data, length, pDexFile))
goto bail;
/* ignore the opt header and appended data from here on out */
data += pDexFile->pOptHeader->dexOffset;
length -= pDexFile->pOptHeader->dexOffset;
if (pDexFile->pOptHeader->dexLength > length) {
ALOGE("File truncated? stored len=%d, rem len=%d",
pDexFile->pOptHeader->dexLength, (int) length);
goto bail;
}
length = pDexFile->pOptHeader->dexLength;
}
dexFileSetupBasicPointers(pDexFile, data);
pHeader = pDexFile->pHeader;
if (!dexHasValidMagic(pHeader)) {
goto bail;
}
/*
* Verify the checksum(s). This is reasonably quick, but does require
* touching every byte in the DEX file. The base checksum changes after
* byte-swapping and DEX optimization.
*/
if (flags & kDexParseVerifyChecksum) {
u4 adler = dexComputeChecksum(pHeader);
if (adler != pHeader->checksum) {
ALOGE("ERROR: bad checksum (%08x vs %08x)",
adler, pHeader->checksum);
if (!(flags & kDexParseContinueOnError))
goto bail;
} else {
ALOGV("+++ adler32 checksum (%08x) verified", adler);
}
const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
if (pOptHeader != NULL) {
adler = dexComputeOptChecksum(pOptHeader);
if (adler != pOptHeader->checksum) {
ALOGE("ERROR: bad opt checksum (%08x vs %08x)",
adler, pOptHeader->checksum);
if (!(flags & kDexParseContinueOnError))
goto bail;
} else {
ALOGV("+++ adler32 opt checksum (%08x) verified", adler);
}
}
}
/*
* Verify the SHA-1 digest. (Normally we don't want to do this --
* the digest is used to uniquely identify the original DEX file, and
* can't be computed for verification after the DEX is byte-swapped
* and optimized.)
*/
if (kVerifySignature) {
unsigned char sha1Digest[kSHA1DigestLen];
const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) +
kSHA1DigestLen;
dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest);
if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) {
char tmpBuf1[kSHA1DigestOutputLen];
char tmpBuf2[kSHA1DigestOutputLen];
ALOGE("ERROR: bad SHA1 digest (%s vs %s)",
dexSHA1DigestToStr(sha1Digest, tmpBuf1),
dexSHA1DigestToStr(pHeader->signature, tmpBuf2));
if (!(flags & kDexParseContinueOnError))
goto bail;
} else {
ALOGV("+++ sha1 digest verified");
}
}
if (pHeader->fileSize != length) {
ALOGE("ERROR: stored file size (%d) != expected (%d)",
(int) pHeader->fileSize, (int) length);
if (!(flags & kDexParseContinueOnError))
goto bail;
}
if (pHeader->classDefsSize == 0) {
ALOGE("ERROR: DEX file has no classes in it, failing");
goto bail;
}
/*
* Success!
*/
result = 0;
bail:
if (result != 0 && pDexFile != NULL) {
dexFileFree(pDexFile);
pDexFile = NULL;
}
return pDexFile;
}
/*
* Free up the DexFile and any associated data structures.
*
* Note we may be called with a partially-initialized DexFile.
*/
void dexFileFree(DexFile* pDexFile)
{
if (pDexFile == NULL)
return;
free(pDexFile);
}
/*
* Look up a class definition entry by descriptor.
*
* "descriptor" should look like "Landroid/debug/Stuff;".
*/
const DexClassDef* dexFindClass(const DexFile* pDexFile,
const char* descriptor)
{
const DexClassLookup* pLookup = pDexFile->pClassLookup;
u4 hash;
int idx, mask;
hash = classDescriptorHash(descriptor);
mask = pLookup->numEntries - 1;
idx = hash & mask;
/*
* Search until we find a matching entry or an empty slot.
*/
while (true) {
int offset;
offset = pLookup->table[idx].classDescriptorOffset;
if (offset == 0)
return NULL;
if (pLookup->table[idx].classDescriptorHash == hash) {
const char* str;
str = (const char*) (pDexFile->baseAddr + offset);
if (strcmp(str, descriptor) == 0) {
return (const DexClassDef*)
(pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
}
}
idx = (idx + 1) & mask;
}
}
/*
* Compute the DEX file checksum for a memory-mapped DEX file.
*/
u4 dexComputeChecksum(const DexHeader* pHeader)
{
const u1* start = (const u1*) pHeader;
uLong adler = adler32(0L, Z_NULL, 0);
const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum);
}
/*
* Compute the size, in bytes, of a DexCode.
*/
size_t dexGetDexCodeSize(const DexCode* pCode)
{
/*
* The catch handler data is the last entry. It has a variable number
* of variable-size pieces, so we need to create an iterator.
*/
u4 handlersSize;
u4 offset;
u4 ui;
if (pCode->triesSize != 0) {
handlersSize = dexGetHandlersSize(pCode);
offset = dexGetFirstHandlerOffset(pCode);
} else {
handlersSize = 0;
offset = 0;
}
for (ui = 0; ui < handlersSize; ui++) {
DexCatchIterator iterator;
dexCatchIteratorInit(&iterator, pCode, offset);
offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
}
const u1* handlerData = dexGetCatchHandlerData(pCode);
//ALOGD("+++ pCode=%p handlerData=%p last offset=%d",
// pCode, handlerData, offset);
/* return the size of the catch handler + everything before it */
return (handlerData - (u1*) pCode) + offset;
}
/*
* Round up to the next highest power of 2.
*
* Found on http://graphics.stanford.edu/~seander/bithacks.html.
*/
u4 dexRoundUpPower2(u4 val)
{
val--;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val++;
return val;
}
- //
- // DexHacker.h
- //
- //
- // Created by BunnyBlue on 6/23/15.
- //
- //
- #ifndef ____DexHacker__
- #define ____DexHacker__
- #include <iostream>
- #include<string.h>
- #include<stdio.h>
- #include "base64.h"
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #define BUFLEN 1024
- class DexHacker{
- public:
- void writeDex2Encoded(unsigned char * data,size_t length);
- void writeEncodedDex2Dex(const char *dexPath);
- char * getProcessName(char * buffer);
- };
- #endif /* defined(____DexHacker__) */
//
// DexHacker.h
//
//
// Created by BunnyBlue on 6/23/15.
//
//
#ifndef ____DexHacker__
#define ____DexHacker__
#include <iostream>
#include<string.h>
#include<stdio.h>
#include "base64.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#define BUFLEN 1024
class DexHacker{
public:
void writeDex2Encoded(unsigned char * data,size_t length);
void writeEncodedDex2Dex(const char *dexPath);
char * getProcessName(char * buffer);
};
#endif /* defined(____DexHacker__) */
- /**
- * \file base64.h
- *
- * \brief RFC 1521 base64 encoding/decoding
- *
- * Copyright (C) 2006-2010, Brainspark B.V.
- *
- * This file is part of PolarSSL (http://www.polarssl.org)
- * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #define POLARSSL_BASE64_C
- #define POLARSSL_SELF_TEST
- #ifndef POLARSSL_BASE64_H
- #define POLARSSL_BASE64_H
- #include <string.h>
- #define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */
- #define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */
- #ifdef __cplusplus
- extern "C" {
- #endif
- /**
- * \brief Encode a buffer into base64 format
- *
- * \param dst destination buffer
- * \param dlen size of the buffer
- * \param src source buffer
- * \param slen amount of data to be encoded
- *
- * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL.
- * *dlen is always updated to reflect the amount
- * of data that has (or would have) been written.
- *
- * \note Call this function with *dlen = 0 to obtain the
- * required buffer size in *dlen
- */
- int base64_encode( unsigned char *dst, size_t *dlen,
- const unsigned char *src, size_t slen );
- /**
- * \brief Decode a base64-formatted buffer
- *
- * \param dst destination buffer
- * \param dlen size of the buffer
- * \param src source buffer
- * \param slen amount of data to be decoded
- *
- * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
- * POLARSSL_ERR_BASE64_INVALID_CHARACTER if the input data is
- * not correct. *dlen is always updated to reflect the amount
- * of data that has (or would have) been written.
- *
- * \note Call this function with *dlen = 0 to obtain the
- * required buffer size in *dlen
- */
- int base64_decode( unsigned char *dst, size_t *dlen,
- const unsigned char *src, size_t slen );
- int base64_self_test( int verbose );
- #ifdef __cplusplus
- }
- #endif
- #endif /* base64.h */
/**
* \file base64.h
*
* \brief RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define POLARSSL_BASE64_C
#define POLARSSL_SELF_TEST
#ifndef POLARSSL_BASE64_H
#define POLARSSL_BASE64_H
#include <string.h>
#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */
#define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Encode a buffer into base64 format
*
* \param dst destination buffer
* \param dlen size of the buffer
* \param src source buffer
* \param slen amount of data to be encoded
*
* \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL.
* *dlen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_encode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen );
/**
* \brief Decode a base64-formatted buffer
*
* \param dst destination buffer
* \param dlen size of the buffer
* \param src source buffer
* \param slen amount of data to be decoded
*
* \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
* POLARSSL_ERR_BASE64_INVALID_CHARACTER if the input data is
* not correct. *dlen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_decode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen );
int base64_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* base64.h */
- /*
- * RFC 1521 base64 encoding/decoding
- *
- * Copyright (C) 2006-2013, Brainspark B.V.
- *
- * This file is part of PolarSSL (http://www.polarssl.org)
- * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #define POLARSSL_BASE64_C
- #define POLARSSL_SELF_TEST
- #if defined(POLARSSL_BASE64_C)
- #include "base64.h"
- #if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
- #include <basetsd.h>
- typedef UINT32 uint32_t;
- #else
- #include <inttypes.h>
- #endif
- static const unsigned char base64_enc_map[64] =
- {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
- 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '+', '/'
- };
- static const unsigned char base64_dec_map[128] =
- {
- 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
- 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 127, 127, 127, 127, 127
- };
- /*
- * Encode a buffer into base64 format
- */
- int base64_encode( unsigned char *dst, size_t *dlen,
- const unsigned char *src, size_t slen )
- {
- size_t i, n;
- int C1, C2, C3;
- unsigned char *p;
- if( slen == 0 )
- return( 0 );
- n = (slen << 3) / 6;
- switch( (slen << 3) - (n * 6) )
- {
- case 2: n += 3; break;
- case 4: n += 2; break;
- default: break;
- }
- if( *dlen < n + 1 )
- {
- *dlen = n + 1;
- return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
- }
- n = (slen / 3) * 3;
- for( i = 0, p = dst; i < n; i += 3 )
- {
- C1 = *src++;
- C2 = *src++;
- C3 = *src++;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
- *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
- *p++ = base64_enc_map[C3 & 0x3F];
- }
- if( i < slen )
- {
- C1 = *src++;
- C2 = ((i + 1) < slen) ? *src++ : 0;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
- if( (i + 1) < slen )
- *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
- else *p++ = '=';
- *p++ = '=';
- }
- *dlen = p - dst;
- *p = 0;
- return( 0 );
- }
- /*
- * Decode a base64-formatted buffer
- */
- int base64_decode( unsigned char *dst, size_t *dlen,
- const unsigned char *src, size_t slen )
- {
- size_t i, n;
- uint32_t j, x;
- unsigned char *p;
- for( i = n = j = 0; i < slen; i++ )
- {
- if( ( slen - i ) >= 2 &&
- src[i] == '\r' && src[i + 1] == '\n' )
- continue;
- if( src[i] == '\n' )
- continue;
- if( src[i] == '=' && ++j > 2 )
- return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
- if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
- return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
- if( base64_dec_map[src[i]] < 64 && j != 0 )
- return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
- n++;
- }
- if( n == 0 )
- return( 0 );
- n = ((n * 6) + 7) >> 3;
- if( dst == NULL || *dlen < n )
- {
- *dlen = n;
- return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
- }
- for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
- {
- if( *src == '\r' || *src == '\n' )
- continue;
- j -= ( base64_dec_map[*src] == 64 );
- x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
- if( ++n == 4 )
- {
- n = 0;
- if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
- if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
- if( j > 2 ) *p++ = (unsigned char)( x );
- }
- }
- *dlen = p - dst;
- return( 0 );
- }
- #if defined(POLARSSL_SELF_TEST)
- #include <string.h>
- #include <stdio.h>
- static const unsigned char base64_test_dec[64] =
- {
- 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
- 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
- 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
- 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
- 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
- 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
- 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
- 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
- };
- static const unsigned char base64_test_enc[] =
- "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
- "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
- /*
- * Checkup routine
- */
- int base64_self_test( int verbose )
- {
- size_t len;
- const unsigned char *src;
- unsigned char buffer[128];
- if( verbose != 0 )
- printf( " Base64 encoding test: " );
- len = sizeof( buffer );
- src = base64_test_dec;
- if( base64_encode( buffer, &len, src, 64 ) != 0 ||
- memcmp( base64_test_enc, buffer, 88 ) != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
- return( 1 );
- }
- if( verbose != 0 )
- printf( "passed\n Base64 decoding test: " );
- len = sizeof( buffer );
- src = base64_test_enc;
- if( base64_decode( buffer, &len, src, 88 ) != 0 ||
- memcmp( base64_test_dec, buffer, 64 ) != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
- return( 1 );
- }
- if( verbose != 0 )
- printf( "passed\n\n" );
- return( 0 );
- }
- #endif
- #endif
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define POLARSSL_BASE64_C
#define POLARSSL_SELF_TEST
#if defined(POLARSSL_BASE64_C)
#include "base64.h"
#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
static const unsigned char base64_enc_map[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
static const unsigned char base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
/*
* Encode a buffer into base64 format
*/
int base64_encode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen )
{
size_t i, n;
int C1, C2, C3;
unsigned char *p;
if( slen == 0 )
return( 0 );
n = (slen << 3) / 6;
switch( (slen << 3) - (n * 6) )
{
case 2: n += 3; break;
case 4: n += 2; break;
default: break;
}
if( *dlen < n + 1 )
{
*dlen = n + 1;
return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
}
n = (slen / 3) * 3;
for( i = 0, p = dst; i < n; i += 3 )
{
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if( i < slen )
{
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if( (i + 1) < slen )
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else *p++ = '=';
*p++ = '=';
}
*dlen = p - dst;
*p = 0;
return( 0 );
}
/*
* Decode a base64-formatted buffer
*/
int base64_decode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen )
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
for( i = n = j = 0; i < slen; i++ )
{
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
if( src[i] == '=' && ++j > 2 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
if( base64_dec_map[src[i]] < 64 && j != 0 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
n++;
}
if( n == 0 )
return( 0 );
n = ((n * 6) + 7) >> 3;
if( dst == NULL || *dlen < n )
{
*dlen = n;
return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' )
continue;
j -= ( base64_dec_map[*src] == 64 );
x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*dlen = p - dst;
return( 0 );
}
#if defined(POLARSSL_SELF_TEST)
#include <string.h>
#include <stdio.h>
static const unsigned char base64_test_dec[64] =
{
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
};
static const unsigned char base64_test_enc[] =
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
/*
* Checkup routine
*/
int base64_self_test( int verbose )
{
size_t len;
const unsigned char *src;
unsigned char buffer[128];
if( verbose != 0 )
printf( " Base64 encoding test: " );
len = sizeof( buffer );
src = base64_test_dec;
if( base64_encode( buffer, &len, src, 64 ) != 0 ||
memcmp( base64_test_enc, buffer, 88 ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n Base64 decoding test: " );
len = sizeof( buffer );
src = base64_test_enc;
if( base64_decode( buffer, &len, src, 88 ) != 0 ||
memcmp( base64_test_dec, buffer, 64 ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n\n" );
return( 0 );
}
#endif
#endif
- # Copyright (C) 2008 The Android Open Source Project
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- LOCAL_PATH:= $(call my-dir)
- dex_src_files := \
- CmdUtils.cpp \
- DexCatch.cpp \
- DexClass.cpp \
- DexDataMap.cpp \
- DexDebugInfo.cpp \
- DexFile.cpp \
- DexInlines.cpp \
- DexOptData.cpp \
- DexOpcodes.cpp \
- DexProto.cpp \
- DexSwapVerify.cpp \
- DexUtf.cpp \
- InstrUtils.cpp \
- Leb128.cpp \
- OptInvocation.cpp \
- sha1.cpp \
- SysUtil.cpp \
- ZipArchive.cpp\
- base64.c
- dex_include_files := \
- dalvik \
- external/zlib \
- external/safe-iop/include
- ##
- ##
- ## Build the device version of libdex
- ##
- ##
- ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
- include $(CLEAR_VARS)
- LOCAL_CFLAGS += -DCODE_DVM -fpermissive
- LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
- LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
- #LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
- LOCAL_SRC_FILES := $(dex_src_files)
- LOCAL_C_INCLUDES += $(dex_include_files)
- LOCAL_STATIC_LIBRARIES := liblog
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := libdex
- include $(BUILD_STATIC_LIBRARY)
- endif # !SDK_ONLY
- ##
- ##
- ## Build the host version of libdex
- ##
- ##
- include $(CLEAR_VARS)
- LOCAL_CFLAGS += -DCODE_DVM
- LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
- LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
- LOCAL_SRC_FILES := $(dex_src_files)
- LOCAL_C_INCLUDES += $(dex_include_files)
- LOCAL_STATIC_LIBRARIES := liblog
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := libdex
- include $(BUILD_HOST_STATIC_LIBRARY)
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH:= $(call my-dir)
dex_src_files := \
CmdUtils.cpp \
DexCatch.cpp \
DexClass.cpp \
DexDataMap.cpp \
DexDebugInfo.cpp \
DexFile.cpp \
DexInlines.cpp \
DexOptData.cpp \
DexOpcodes.cpp \
DexProto.cpp \
DexSwapVerify.cpp \
DexUtf.cpp \
InstrUtils.cpp \
Leb128.cpp \
OptInvocation.cpp \
sha1.cpp \
SysUtil.cpp \
ZipArchive.cpp\
base64.c
dex_include_files := \
dalvik \
external/zlib \
external/safe-iop/include
##
##
## Build the device version of libdex
##
##
ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DCODE_DVM -fpermissive
LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_STATIC_LIBRARY)
endif # !SDK_ONLY
##
##
## Build the host version of libdex
##
##
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DCODE_DVM
LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_HOST_STATIC_LIBRARY)