var soAddr = Module.findBaseAddress("libxiaojianbang.so"); varMD5Final = soAddr.add(0x3A78); Interceptor.attach(MD5Final, { onEnter: function (args) { this.args1 = args[1]; }, onLeave: function (retval) { console.log(hexdump(this.args1)); } }); /* 7ffc689cc8 41 be f1 ce 7f dc 3e 42 c0 e5 d9 40 ad 74 ac 00 A.....>B...@.t.. //logcat中的输出结果 //CMD5 md5Result: 41bef1ce7fdc3e42c0e5d940ad74ac00 */
varRegisterNativesAddr = null; var _symbols = Process.findModuleByName("libart.so").enumerateSymbols(); for (var i = 0; i < _symbols.length; i++) { var _symbol = _symbols[i]; if (_symbol.name.indexOf("CheckJNI") == -1 && _symbol.name.indexOf("RegisterNatives") != -1) { RegisterNativesAddr = _symbols[i].address; } }
Interceptor.attach(RegisterNativesAddr, { onEnter: function (args) { var env = Java.vm.tryGetEnv(); var className = env.getClassName(args[1]); var methodCount = args[3].toInt32();
for (let i = 0; i < methodCount; i++) { var methodName = args[2].add(Process.pointerSize * 3 * i) .readPointer().readCString(); var signature = args[2].add(Process.pointerSize * 3 * i) .add(Process.pointerSize).readPointer().readCString(); var fnPtr = args[2].add(Process.pointerSize * 3 * i) .add(Process.pointerSize * 2).readPointer(); varmodule = Process.findModuleByAddress(fnPtr); console.log(className, methodName, signature, fnPtr, module.name, fnPtr.sub(module.base)); } }, onLeave: function (retval) { } });
var jSONObject = Java.use("org.json.JSONObject"); jSONObject.put.overload('java.lang.String', 'java.lang.Object').implementation = function (a, b) { showStacks(); console.log("JSONObject.put: ", a, b); returnthis.put(a, b); } jSONObject.getString.implementation = function (a) { showStacks(); var result = this.getString(a); console.log("JSONObject.getString: ", a, result); return result; }
var funcAddr = Module.findBaseAddress("libxiaojianbang.so").add(0x1ACC); var asm = Instruction.parse(funcAddr); console.log(asm); for (var i = 0; i < 3; i++) { asm = Instruction.parse(asm.next); console.log(asm); }
//为了读写并dump文件的函数 functionget_self_process_name() { var openPtr = Module.getExportByName('libc.so', 'open'); var open = newNativeFunction(openPtr, 'int', ['pointer', 'int']);
var readPtr = Module.getExportByName("libc.so", "read"); var read = newNativeFunction(readPtr, "int", ["int", "pointer", "int"]);
var closePtr = Module.getExportByName('libc.so', 'close'); var close = newNativeFunction(closePtr, 'int', ['int']);
var path = Memory.allocUtf8String("/proc/self/cmdline"); var fd = open(path, 0); if (fd != -1) { var buffer = Memory.alloc(0x1000);
var result = read(fd, buffer, 0x1000); close(fd); result = ptr(buffer).readCString(); return result; }
return"-1"; }
//这玩意儿跟dump so差不多 functiondump_dex() { var libart = Process.findModuleByName("libart.so"); var addr_DefineClass = null; var symbols = libart.enumerateSymbols(); for (var index = 0; index < symbols.length; index++) { var symbol = symbols[index]; var symbol_name = symbol.name; //这个DefineClass的函数签名是Android9的 //_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefE if (symbol_name.indexOf("ClassLinker") >= 0 && symbol_name.indexOf("DefineClass") >= 0 && symbol_name.indexOf("Thread") >= 0 && symbol_name.indexOf("DexFile") >= 0 ) { console.log(symbol_name, symbol.address); addr_DefineClass = symbol.address; } } var dex_maps = {};
console.log("[DefineClass:]", addr_DefineClass); if (addr_DefineClass) { Interceptor.attach(addr_DefineClass, { onEnter: function (args) { var dex_file = args[5]; //ptr(dex_file).add(Process.pointerSize) is "const uint8_t* const begin_;" //ptr(dex_file).add(Process.pointerSize + Process.pointerSize) is "const size_t size_;" var base = ptr(dex_file).add(Process.pointerSize).readPointer(); var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();
if (dex_maps[base] == undefined) { dex_maps[base] = size; var magic = ptr(base).readCString(); if (magic.indexOf("dex") == 0) { var process_name = get_self_process_name(); if (process_name != "-1") { var dex_path = "/data/data/" + process_name + "/files/" + base.toString(16) + "_" + size.toString(16) + ".dex"; console.log("[find dex]:", dex_path); var fd = newFile(dex_path, "wb"); if (fd && fd != null) { var dex_buffer = ptr(base).readByteArray(size); fd.write(dex_buffer); fd.flush(); fd.close(); console.log("[dump dex]:", dex_path);
} } } } }, onLeave: function (retval) { } }); } }
var is_hook_libart = false;
//这个也是将dlopen和android_dlopen_ext都给Hook了 functionhook_dlopen() { Interceptor.attach(Module.findExportByName(null, "dlopen"), { onEnter: function (args) { var pathptr = args[0]; if (pathptr !== undefined && pathptr != null) { var path = ptr(pathptr).readCString(); //console.log("dlopen:", path); if (path.indexOf("libart.so") >= 0) { this.can_hook_libart = true; console.log("[dlopen:]", path); } } }, onLeave: function (retval) { if (this.can_hook_libart && !is_hook_libart) { dump_dex(); is_hook_libart = true; } } })
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), { onEnter: function (args) { var pathptr = args[0]; if (pathptr !== undefined && pathptr != null) { var path = ptr(pathptr).readCString(); //console.log("android_dlopen_ext:", path); if (path.indexOf("libart.so") >= 0) { this.can_hook_libart = true; console.log("[android_dlopen_ext:]", path); } } }, onLeave: function (retval) { if (this.can_hook_libart && !is_hook_libart) { dump_dex(); is_hook_libart = true; } } }); }
setImmediate(hook_dlopen);
加密的字符串解密
这个emmm
直接打印内存中的字符串,以某一偏移地址为例
1 2 3 4 5
var soAddr = Module.findBaseAddress("liblogin_encrypt.so"); console.log(soAddr.add(0xD060).readCString()); // java/security/KeyFactory //这个用的不是HookDemo //在这链接:https://pan.baidu.com/s/1qsdNfpmOMVjfpw3pQfYGTA?pwd=GAME 提取码:GAME
var fopenAddr = Module.findExportByName("libc.so", "fopen"); var fputsAddr = Module.findExportByName("libc.so", "fputs"); var fcloseAddr = Module.findExportByName("libc.so", "fclose");
// FILE *fopen(const char *filename, const char *mode) // int fputs(const char *str, FILE *stream) // int fclose(FILE *stream) var fopen = newNativeFunction(fopenAddr, "pointer", ["pointer", "pointer"]); var fputs = newNativeFunction(fputsAddr, "int", ["pointer", "pointer"]); var fclose = newNativeFunction(fcloseAddr, "int", ["pointer"]);
var fileName = Memory.allocUtf8String("/data/data/com.xiaojianbang.app/xiaojianbang.txt"); var openMode = Memory.allocUtf8String("w"); var buffer = Memory.allocUtf8String("111111111");
var file = fopen(filename, open_mode); fputs(buffer, file); fclose(file);
var fopenAddr = Module.findExportByName("libc.so", "fopen"); var fgetsAddr = Module.findExportByName("libc.so", "fgets"); var fcloseAddr = Module.findExportByName("libc.so", "fclose");
// char *fgets(char *str, int n, FILE *stream) var fopen = newNativeFunction(fopenAddr, "pointer", ["pointer", "pointer"]); var fgets = newNativeFunction(fgetsAddr, "pointer", ["pointer", "int", "pointer"]); var fclose = newNativeFunction(fcloseAddr, "int", ["pointer"]);
var fileName = Memory.allocUtf8String("/data/data/com.xiaojianbang.app/xiaojianbang.txt"); var openMode = Memory.allocUtf8String("r"); var buffer = Memory.alloc(60);
var file = fopen(fileName, openMode); var data = fgets(buffer, 60, file); console.log(data.readCString()); fclose(file);
//The __filename and __flags arguments are the same as for dlopen(3), with the Android-specific flags supplied via the flags member of __info.Available since API level 21.
PIMAGE_DOS_HEADER P_DosHeader;////定义指向_IMAGE_DOS_HEADER结构体的指针 P_DosHeader = (PIMAGE_DOS_HEADER)buffer;//在编写这一步的时候,我忽视了buffer的字节大小和指针的字节大小不对等(因为我刚开始定义buffer疏忽了将其作为指针来定义),从而触发warning: cast to pointer from integer of different size [-Wint-to-pointer-cast],buffer改为指针类型即可解决该warning printf("Info as follow:\n"); printf("The Flag bit of this file is %X\n", P_DosHeader->e_magic); printf("The offset of the DOS header is:%X\n", P_DosHeader->e_lfanew);
输出如下图所示
可以看到,正确的。
当然我们也可以为MZ加个判断
1 2 3 4 5
if(P_DosHeader->e_magic != IMAGE_DOS_SIGNATURE)//5A4D-"ZM",4D5A-"MZ" { printf("This file is not a PE file!\n"); return0; }
//解析PE文件头 PIMAGE_NT_HEADERS32 P_NtHeader; //定义指向_IMAGE_NT_HEADERS32结构体的指针 P_NtHeader = (PIMAGE_NT_HEADERS32)(buffer + P_DosHeader->e_lfanew); printf("The Flag bit of this file is %X\n", P_NtHeader->Signature); printf("Machine: %X\n", P_NtHeader->FileHeader.Machine); printf("Number of Sections: %d\n", P_NtHeader->FileHeader.NumberOfSections); printf("Characteristics: %X\n", P_NtHeader->FileHeader.Characteristics);
printf("The follow is the info of PE file optional header:\n"); printf("Magic: %X\n", P_NtHeader->OptionalHeader.Magic); //这个值是0x10B,表示PE32,0x20B表示PE32+(64位) printf("AddressOfEntryPoint: %X\n", P_NtHeader->OptionalHeader.AddressOfEntryPoint);//这项可以告诉我们程序的入口地址 printf("ImageBase: %X\n", P_NtHeader->OptionalHeader.ImageBase);//这个值是文件的起始地址,也就是我们要解析的文件的起始地址 printf("SectionAlignment: %X\n", P_NtHeader->OptionalHeader.SectionAlignment);//节区对齐值 printf("FileAlignment: %X\n", P_NtHeader->OptionalHeader.FileAlignment);//文件对齐值 printf("SizeOfImage: %X\n", P_NtHeader->OptionalHeader.SizeOfImage);//文件大小 printf("SizeOfHeaders: %X\n", P_NtHeader->OptionalHeader.SizeOfHeaders);//头部大小 printf("CheckSum: %X\n", P_NtHeader->OptionalHeader.CheckSum);//映像校验和,用处就是用来检验文件是否被修改过。 printf("Subsystem: %X\n", P_NtHeader->OptionalHeader.Subsystem);//子系统 printf("NumberOfRvaAndSizes: %X\n", P_NtHeader->OptionalHeader.NumberOfRvaAndSizes);//RVA和Sizes的数量 printf("Number Of Data Directories: %X\n", P_NtHeader->OptionalHeader.NumberOfRvaAndSizes);//数据目录的数量 printf("------------------------Thats's basic info of OPTIONAL_HEADER----------------------------\n"); printf("\n"); printf("------------------------Next are some tables----------------------------\n"); printf("\n"); //解析DATA_DIRECTORY printf("The follow is the info of PE file data directory:\n"); printf("Address of Export Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[0].VirtualAddress); printf("Size of Export Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[0].Size); printf("Address of Import Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[1].VirtualAddress); printf("Size of Import Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[1].Size); printf("Address of Resource Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[2].VirtualAddress); printf("Size of Resource Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[2].Size); printf("Address of TLS Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[9].VirtualAddress); printf("Size of TLS Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[9].Size); printf("Address of IAT: %X\n", P_NtHeader->OptionalHeader.DataDirectory[12].VirtualAddress); printf("Size of IAT: %X\n", P_NtHeader->OptionalHeader.DataDirectory[12].Size); printf("------------------------Thats's basic info of DATA_DIRECTORY----------------------------\n"); printf("\n");
printf("The follow is the info of PE file section header:\n"); PIMAGE_SECTION_HEADER P_SectionHeader; P_SectionHeader = (PIMAGE_SECTION_HEADER)(buffer + P_DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32)); for(int i = 0; i < P_NtHeader->FileHeader.NumberOfSections; i++) { printf("Section Name: %s\n", P_SectionHeader->Name); printf("Virtual Address: %X\n", P_SectionHeader->VirtualAddress); printf("Size of Raw Data: %X\n", P_SectionHeader->SizeOfRawData); printf("Pointer to Raw Data: %X\n", P_SectionHeader->PointerToRawData); printf("Pointer to Relocations: %X\n", P_SectionHeader->PointerToRelocations); printf("Pointer to Linenumbers: %X\n", P_SectionHeader->PointerToLinenumbers); printf("Number of Relocations: %X\n", P_SectionHeader->NumberOfRelocations); printf("Number of Linenumbers: %X\n", P_SectionHeader->NumberOfLinenumbers); printf("Characteristics: %X\n", P_SectionHeader->Characteristics); printf("------------------------Thats's basic info of SECTION----------------------------\n"); printf("\n");
printf("Please input the path of the file you want to look by my parser of PE:\n"); gets(path); fopen_s(&pFile,path, "rb"); if(pFile == NULL) { printf("Open file failed,maybe it's doesn't exist?\n"); return0; } fseek(pFile, 0, SEEK_END); //允许文件读写位置移动到文件尾,返回文件长度 nFileLength = ftell(pFile); //获取文件长度 if(nFileLength == 0) { printf("The file is empty!\n"); return0; } rewind(pFile); //将文件指针重新指向文件开头 //接下来为文件分配空间 int ImageBase = nFileLength * sizeof(char) + 1; buffer = (char*)malloc(ImageBase); memset(buffer, 0, nFileLength * sizeof(char) + 1); //读取文件内容 fread(buffer, 1, ImageBase, pFile); //至此,文件读取操作完成
PIMAGE_DOS_HEADER P_DosHeader; //定义指向_IMAGE_DOS_HEADER结构体的指针 P_DosHeader = (PIMAGE_DOS_HEADER)buffer; printf("Basic Info is as follow:\n"); printf("The Flag bit of this file is %X\n", P_DosHeader->e_magic); printf("The offset of the DOS header is:%X\n", P_DosHeader->e_lfanew); printf("------------------------Thats's basic info of DosHeaderStruct----------------------------\n"); printf("\n"); if(P_DosHeader->e_magic != IMAGE_DOS_SIGNATURE)//判断是否为PE文件 { printf("This file is not a PE file!\n"); return0; } //解析PE文件头 //解析FILE_HEADER PIMAGE_NT_HEADERS32 P_NtHeader; //定义指向_IMAGE_NT_HEADERS32结构体的指针 P_NtHeader = (PIMAGE_NT_HEADERS32)(buffer + P_DosHeader->e_lfanew); printf("The follow is the info of PE file header:\n"); printf("The Flag bit of this file is %X\n", P_NtHeader->Signature); printf("Machine: %X\n", P_NtHeader->FileHeader.Machine); printf("Number of Sections: %d\n", P_NtHeader->FileHeader.NumberOfSections); printf("Characteristics: %X\n", P_NtHeader->FileHeader.Characteristics); /*printf("TimeDateStamp: %X\n", P_NtHeader->FileHeader.TimeDateStamp);//这项可以告诉我们编译器创建文件的时间,注释掉吧,感觉没用过*/ printf("------------------------Thats's basic info of FILE_HEADER----------------------------\n"); printf("\n"); //解析OPTIONAL_HEADER printf("The follow is the info of PE file optional header:\n"); printf("Magic: %X\n", P_NtHeader->OptionalHeader.Magic); //这个值是0x10B,表示PE32,0x20B表示PE32+(64位) printf("AddressOfEntryPoint: %X\n", P_NtHeader->OptionalHeader.AddressOfEntryPoint);//这项可以告诉我们程序的入口地址 printf("ImageBase: %X\n", P_NtHeader->OptionalHeader.ImageBase);//这个值是文件的起始地址,也就是我们要解析的文件的起始地址 printf("SectionAlignment: %X\n", P_NtHeader->OptionalHeader.SectionAlignment);//节区对齐值 printf("FileAlignment: %X\n", P_NtHeader->OptionalHeader.FileAlignment);//文件对齐值 printf("SizeOfImage: %X\n", P_NtHeader->OptionalHeader.SizeOfImage);//文件大小 printf("SizeOfHeaders: %X\n", P_NtHeader->OptionalHeader.SizeOfHeaders);//头部大小 printf("CheckSum: %X\n", P_NtHeader->OptionalHeader.CheckSum);//映像校验和,用处就是用来检验文件是否被修改过。 printf("Subsystem: %X\n", P_NtHeader->OptionalHeader.Subsystem);//子系统 printf("NumberOfRvaAndSizes: %X\n", P_NtHeader->OptionalHeader.NumberOfRvaAndSizes);//RVA和Sizes的数量 printf("Number Of Data Directories: %X\n", P_NtHeader->OptionalHeader.NumberOfRvaAndSizes);//数据目录的数量 printf("------------------------Thats's basic info of OPTIONAL_HEADER----------------------------\n"); printf("\n"); printf("------------------------Next are some tables----------------------------\n"); printf("\n"); //解析DATA_DIRECTORY printf("The follow is the info of PE file data directory:\n"); printf("Address of Export Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[0].VirtualAddress); printf("Size of Export Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[0].Size); printf("Address of Import Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[1].VirtualAddress); printf("Size of Import Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[1].Size); printf("Address of Resource Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[2].VirtualAddress); printf("Size of Resource Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[2].Size); printf("Address of TLS Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[9].VirtualAddress); printf("Size of TLS Table: %X\n", P_NtHeader->OptionalHeader.DataDirectory[9].Size); printf("Address of IAT: %X\n", P_NtHeader->OptionalHeader.DataDirectory[12].VirtualAddress); printf("Size of IAT: %X\n", P_NtHeader->OptionalHeader.DataDirectory[12].Size); printf("------------------------Thats's basic info of DATA_DIRECTORY----------------------------\n"); printf("\n"); //解析SECTION_HEADER printf("The follow is the info of PE file section header:\n"); PIMAGE_SECTION_HEADER P_SectionHeader; P_SectionHeader = (PIMAGE_SECTION_HEADER)(buffer + P_DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32)); for(int i = 0; i < P_NtHeader->FileHeader.NumberOfSections; i++) { printf("Section Name: %s\n", P_SectionHeader->Name); printf("Virtual Address: %X\n", P_SectionHeader->VirtualAddress); printf("Size of Raw Data: %X\n", P_SectionHeader->SizeOfRawData); printf("Pointer to Raw Data: %X\n", P_SectionHeader->PointerToRawData); printf("Pointer to Relocations: %X\n", P_SectionHeader->PointerToRelocations); printf("Pointer to Linenumbers: %X\n", P_SectionHeader->PointerToLinenumbers); printf("Number of Relocations: %X\n", P_SectionHeader->NumberOfRelocations); printf("Number of Linenumbers: %X\n", P_SectionHeader->NumberOfLinenumbers); printf("Characteristics: %X\n", P_SectionHeader->Characteristics); printf("------------------------Thats's basic info of SECTION----------------------------\n"); printf("\n"); P_SectionHeader++; } printf("Please input which information you want to look :\n"); printf("1.Export Table\n"); printf("2.Import Table\n"); printf("3.TLS Table\n"); printf("4.exit\n"); int choice; while(1) { printf("Input a number: "); scanf("%d", &choice); if (choice == 1) ExportTable(buffer); elseif (choice == 2) ImportTable(buffer); elseif (choice == 3) TlsTable(buffer); elseif (choice == 4) return0; else printf("Please input again and make sur that's valid\n"); } system("pause"); free(buffer);//走之前别忘了清空缓存区 return0; }