Objective
This APK uses love encryption encryption, encryption time is 2017.6 months. This problem is actually a shelling problem, take off immediately see flag. (The person is too lazy to do the quiz)
Title Link: https://gitee.com/hac425/blog_data/blob/master/app02.apk
Shell Introduction
Love encrypted shell at the end of 16 has begun hook dvmResolveClass
to pass, when the specific method is called to decrypt the method instruction, and then the dexfile structure of the corresponding method of the direction of the md->insns
decryption method instruction data area, and then into the 真正的dvmResolveClass
execution of instructions, after execution in the re-encryption instructions, This prevents dexhunter
the tool from being used in the in dump dex
-memory file.
Flow chart
Photo source
Shelling
As can be known from above, the dvmResolveClass
code is restored when the function is executed. Then we go to dump
the corresponding instruction is the correct instruction. So modify dvmResolveClass
the code, the dump
method of the data.
To modify a dvmResolveClass
function:
/* Add Dump ... */char key_str[20] = "Jiajiatest"; int Fd=open ("/data/local/tmp/resolve_class_config", o_rdonly,0666); if (fd!=-1) {int len = read (fd,key_str,19); Key_str[len-1] = ' \x00 '; Key_str[len] = ' \x00 '; Close (FD); } alogi ("The KEY_STR--->%s----referrer->descriptor--->%s--", key_str, Referrer->descriptor); if (Strstr (Referrer->descriptor, Key_str)) {char task_name[] = "Task_name"; Char *logbuf = new char[1024]; Char path[50] = {0}; sprintf (Path, "/data/local/tmp/%s_dump_%d", Key_str, Getpid ()); FILE *FPW = fopen (Path, "awb+"); for (int i=0; i < referrer->directmethodcount; i++) {method* MD = &referrer->directMethods[i]; Const char* Mname_d = md->name; Const U2 inssize_d = md->inssize; Const u2* Insns_d = md->insns; Const U2 methodldx_d = md->methodindex; U4 insns_d_size = dvmgetmethodinsnssize (MD);//Alogi ("HACKLH_MD---->%p, i-->%d, dirEctmethodcount-->%d ", MD, I,referrer->directmethodcount); sprintf (Logbuf, "--------------(KL) Resolving [class=%s, method=%s, methodindex=%u, inssize=%u, insns_d=%x, codesize=% D] in PID:%d (name:%s) ", Referrer->descriptor,mname_d,methodldx_d,inssize_d, (U4) Insns_d, Insns_d_size,getpid (), Task_name); LOGD ("%s", logbuf); if (FPW! = NULL) {fwrite (Logbuf,1,strlen (LOGBUF), FPW); Fflush (FPW); Fwrite ((u1*) insns_d,1,insns_d_size*2, FPW); Fflush (FPW); }else{logd ("-(KL) Open%s fail!", path); }} for (int i=0; i < referrer->virtualmethodcount; i++) {method* mv = &referrer->virtualmeth Ods[i]; Const char* MNAME_V = mv->name; Const U2 INSSIZE_V = mv->inssize; Const u2* Insns_v = mv->insns; Const U2 METHODIDX_V = mv->methodindex; U4 insns_v_size = dvmgetmethodinsnssize (mv); sprintf (Logbuf, "--------------(KL) Resolving [class=%s, method=%s, methodindex=%u, inssize=%u, insns_d=%x, codesize=%d] in PID:%d (name:%s) ", Referrer->descriptor,mname_v, Methodidx_v,inssize_v, (U4) Insns_v, Insns_v_size,getpid (), task_name); LOGD ("%s", logbuf); if (FPW! = NULL) {fwrite (Logbuf,1,strlen (LOGBUF), FPW); Fflush (FPW); Fwrite ((u1*) insns_v,1,insns_v_size*2, FPW); Fflush (FPW); }else{logd ("%s", "-(KL) Open file fail!");}} if (FPW! = NULL) {fclose (FPW); } Delete logbuf;/* Add end ... */
After dump we need to patch the instructions to the Dex location, there are many ways to patch it, and I choose to patch it using IDA script. I think Ida is a loader of various file formats, we can modify the contents of the file in Ida, and then let IDA apply the changes to the file to complete the patch. So the patch code in Ida is very handy, and it's easy to see the results after the patch. The process for patch code is:
Method instructions for reading the dump---> locating the location of the corresponding method instruction data area in IDA---->patch
The code is as follows:
#! /usr/bin/python#-*-Coding:utf8-*-# The script is used to use the Dump Method command in Ida Patchimport refrom dex_parser import dex# Storage store du MP data Dictionary data_array = [] #用来避免多次patchpatched = []file_data = "" Def parse_meta_data (Data= ""): # print data ret = {} t Okens = Re.findall ("\[class= (. *?),. *?method= (. *?),. *?codesize= (. *?) \] ", data) # Print tokens ret[' class_name ') = Tokens[0][0][1:].replace ('/', '. '). Replace ('; ', ') ret[' method '] = tokens[0][1] ret[' code_size ') = Int (tokens[0][2]) * 2 #dex文件格式定义, total size is codesize*2 # PRINT RET return ret# comment, used to execute # def patch_byte (A, B) for Ida: # print Hex (b), Def patch (dest, SRC, size): print "dest: : {}, src::{}, size::{} ". Format (dest, SRC, size) for I in range (size): Patch_byte (dest + i, int (file_data[src + I].encode (' hex '), +) print "\ n" def parse_dump_data (filename): Global file_data with open (filename, "RB") as FP: File_data = Fp.read () #使用正则表达式把说明dump数据的元数据加载到内存 All_item = Re.findall ("--------------\ (kl\) resolvING (. *) in pid:.*?\ (name:task_name\) ", file_data) offset = 0 for meta_data in All_item:try: #使用 Dictionary organization Data #{' class_name ': ' com.example.jiajiatest.MainActivity ', ' code_size ': 306, ' method ': ' Add ', ' Data_offset ': 7175} ret = Parse_meta_data (meta_data) data_addr = File_data.find (' (name:task_name) ', offset) + 17 ret[' data_offset ' = data_addr data_array.append (ret) offset = data_addr except E Xception as E:raise e return data_arraydef get_method_addr (Method_data, SIGNATURE_STR): for Md_name in M Ethod_data:if signature_str in Md_name:return method_data[md_name] return-1def patch_dex (dump_data _file, dex_file): Dump_data = Parse_dump_data (dump_data_file) dex_obj = Dex.dex_parser (dex_file) method_data = de X_obj.get_class_data () for item in DUMP_DATA:SIGNATURE_STR = "{}::{}". Format (item[' class_name '], item[' method ') ) If signature_sTR not in patched: #获取要patch的目标地址 addr = get_method_addr (Method_data, SIGNATURE_STR) if a DDR = = -1:print "{} can ' t get Insns addr". Format (SIGNATURE_STR) Continue #do Pat CH print "Patch" + signature_str, Patch (addr,item[' data_offset '],item[' code_size ') PATC Hed.append (SIGNATURE_STR) # Print patched # for i in patched: # Print Iimport pprintpatch_dex ("F:\CODE_WORKPL ace\ida_script\jiajiatest_dump_20406 "," F:\code_workplace\ida_script\classes.dex ") if __name__ = = ' __main__ ': print" comming main "# Parse_dump_data (" F:\code_workplace\ida_script\jiajiatest_dump_20406 ") # Patch_dex (" F:\code_workplac e\ida_script\jiajiatest_dump_20406 "," F:\code_workplace\ida_script\classes.dex ") # dex_obj = Dex.dex_parser (" f:\ Code_workplace\ida_script\classes.dex ") # Class_data = Dex_obj.get_class_data () # Pprint.pprint (class_data) # par Se_meta_data ("--------------(KL) resolving [Class=lcom/example/jiajiatest/httprunner;, Method=makeimghttpget, methodindex=13, insSize=2, insns_d= 6daf04d8, codesize=270] in pid:20406 (name:task_name) ")
Pre-and post-patch comparisons:
Before patch
After patch
You can already see the main logic of the program. Then look at the string to get the flag ...
I did something stupid.
Code loop conditions forgot to write, resulting in a cross-border, an open application on the error.
File open failed, seems to be a privilege issue, I direct violence to /data/local/tmp
change to 777
Summarize
Analyze Android's underlying code errors, follow the logcat
logs, find the offending code point, and then put the signed version of the library into IDA for analysis
To analyze a bug, it depends on the key logic of the code, judging the conditions and so on.
At last
To practice more, please comment below if you have questions.
"Day Wing Cup Android Two" love encryption shelling Combat