Analysis of part 3 Back-debugging Principle
Taking on the previous blog post, there are two problems left when cracking, one is when the static password was modified, the other is the anti-debugging part of the content. Personally, I think the anti-debugging part of the content is more critical, so I will pick up the secret behind it. In this paper, assembly code analysis is the main method, combined with dynamic debugging, my goal is to train and read arm code, improve efficiency is also worth our time.
Or starting with JNI_OnLoad, OnLoad functions mainly do two things:
1. Decrypt dlsym, getpid, sprintf, fopen, fgets, strstr, sscanf, kill, sleep, pthread_create, mprotect, cacheflush, lrand48 and other API strings dynamically, and call dlsym functions to obtain the address of the appeal api, then fill in get (GLOBAL_OFFSET_TABLE) form.
.text:00001BDC ADD R7, R5, #4 .text:00001BE0 MOV R6, #0 .text:00001BE4 .text:00001BE4 loc_1BE4 ; CODE XREF: JNI_OnLoad+5Cj Text: 00001BE4 LDR R0, [R7, R6, LSL_ 2]; Get function pointer Text: 00001BE8 BLX R0; _GLOBAL_OFFSET_TABLE_; Call initIATTable function to decrypt string, initialize get table function, get PID sprintf API address ready after function call.
2. After the api is ready, call pthread_create() to start the debugging detection thread.
.text:00001C28 SUB R5, SP, #8
.text:00001C2C MOV SP, R5
.text:00001C30 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1C48)
.text:00001C34 LDR R1, =(ThreadCallback - 0x5FBC)
.text:00001C38 MOV R3, #0
.text:00001C3C STR R8, [R5]
.text:00001C40 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001C44 ADD R2, R1, R0 ; ThreadCallback
.text:00001C48 ADD R0, R9, R0 ; unk_6290
.text:00001C4C MOV R1, #0 ; name
.text:00001C50 LDR R7, [R0,#(pthread_create_IAT - 0x6290)]
.text:00001C54 SUB R0, R11, #-handle ; handle
.text:00001C58 BLX R7 ; pthread_create(r0,r1,r2);Start Debugging Threads
Here's the Jni_OnLoad function code
.text:00001B9C JNI_OnLoad .text:00001B9C .text:00001B9C handle = -0x20 .text:00001B9C .text:00001B9C STMFD SP!, {R4-R9,R11,LR} .text:00001BA0 ADD R11, SP, #0x18 .text:00001BA4 SUB SP, SP, #8 .text:00001BA8 MOV R4, R0 .text:00001BAC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1BC0) .text:00001BB0 LDR R9, =(unk_6290 - 0x5FBC) .text:00001BB4 MOV R8, #0 .text:00001BB8 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_ Text: 00001BBC ADD R0, R9, R0; unk_6290; get the address of unk_6290 function in get table This is equivalent to the "first address" of the get table. Text: 00001BC0 STR R8, [R0, (dword_62C8-0x6290)]; Initialize the global variable dword_62C8 with a value of 0 .text:00001BC4 LDR R5, [R0,#(dword_62C4 - 0x6290)] ; .text:00001BC8 CMP R5, #0 .text:00001BCC BEQ loc_1C28 if(!dword_62C4) {} .text:00001BD0 .text:00001BD0 loc_1BD0 ; CODE XREF: JNI_OnLoad+74j .text:00001BD0 LDR R0, [R5] .text:00001BD4 CMP R0, #1 .text:00001BD8 BLT loc_1BFC .text:00001BDC ADD R7, R5, #4 .text:00001BE0 MOV R6, #0 .text:00001BE4 .text:00001BE4 loc_1BE4 ; CODE XREF: JNI_OnLoad+5Cj Text: 00001BE4 LDR R0, [R7, R6, LSL_ 2]; Get function pointer Text: 00001BE8 BLX R0; _GLOBAL_OFFSET_TABLE_; Call initIATTable function to decrypt string, initialize get table function, get PID sprintf API address ready after function call. .text:00001BEC LDR R0, [R5] .text:00001BF0 ADD R6, R6, #1 .text:00001BF4 CMP R6, R0 .text:00001BF8 BLT loc_1BE4 ; .text:00001BFC .text:00001BFC loc_1BFC ; CODE XREF: JNI_OnLoad+3Cj .text:00001BFC LDR R6, [R5,#0x2C] .text:00001C00 MOV R0, R5 ; ptr .text:00001C04 BL free_0 .text:00001C08 MOV R5, R6 .text:00001C0C CMP R6, #0 .text:00001C10 BNE loc_1BD0 .text:00001C14 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1C24) .text:00001C18 MOV R1, #0 .text:00001C1C ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_ .text:00001C20 ADD R0, R9, R0 ; unk_6290 .text:00001C24 STR R1, [R0,#(dword_62C4 - 0x6290)] .text:00001C28 .text:00001C28 loc_1C28 ; CODE XREF: JNI_OnLoad+30j .text:00001C28 SUB R5, SP, #8 .text:00001C2C MOV SP, R5 .text:00001C30 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1C48) .text:00001C34 LDR R1, =(ThreadCallback - 0x5FBC) .text:00001C38 MOV R3, #0 .text:00001C3C STR R8, [R5] .text:00001C40 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_ .text:00001C44 ADD R2, R1, R0 ; ThreadCallback .text:00001C48 ADD R0, R9, R0 ; unk_6290 .text:00001C4C MOV R1, #0 ; name .text:00001C50 LDR R7, [R0,#(pthread_create_IAT - 0x6290)] .text:00001C54 SUB R0, R11, #-handle ; handle Text: 00001C58 BLX R7; pthread_create (r0, r1, r2); start debugging thread
initIATTable () function
Main work:
1. Call DecrptionIATTable with decryption key, or DecrptionIATTable 1, or DecrptionIATTable 2. DecrptionIATTable 3 decrypts dlsym, getpid, sprintf, fopen, fgets, strstr, sscanf, kill, sleep, pthread_create, mprotect, etc.
cacheflush, lrand48 string, and mark has been decrypted. Four decryption algorithms are used here, some of them are fantastic.
The following code dlsym has a key of "9HbB" and decrypts the "dlsym" string by calling DecrptionIATTable (). The isDlsymInited global variable is used to set the decrypted flag bit, that is to say, before the next decryption, it will determine whether the string is decrypted or not. If decrypted, it will not need to decrypt again.
.text:00001CDC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1CEC)
.text:00001CE0 LDR R1, =(encrpty_dlsym - 0x5FBC)
.text:00001CE4 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001CE8 ADD R2, R1, R0
.text:00001CEC LDR R1, =(a9hbb - 0x5FBC)key = "9HbB"
.text:00001CF0 ADD R4, R5, R0 ; unk_6290
.text:00001CF4 ADD R3, R1, R0 ; dlsym Decryption key
.text:00001CF8 ADD R0, R4, #0x47
.text:00001CFC MOV R1, #6
.text:00001D00 BL DecrptionIATTable ;Decryption algorithm 1
.text:00001D04 MOV R0, #1
.text:00001D08 STRB R0, [R4,#(isDlsymInited - 0x6290)]
2. Call dlsym(), get the actual memory address one by one, and fill in the get table
.text:00001D74 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1D80)
.text:00001D78 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001D7C ADD R6, R5, R0 ; unk_6290
.text:00001D80 MOV R0, #0xFFFFFFFF
.text:00001D84 ADD R1, R6, #0x5F
.text:00001D88 BLX R4 ; _GLOBAL_OFFSET_TABLE_
.text:00001D8C STR R0, [R6,#(getpid_IAT-0x6290)] Stored in getpid_IAT address
The initIATTable () function code is as follows
initIATTable ; DATA XREF: sub_2378+10o
.text:00001CA8 ; .text:off_2398o
.text:00001CA8
.text:00001CA8 var_20 = -0x20
.text:00001CA8 var_1C = -0x1C
.text:00001CA8
.text:00001CA8 STMFD SP!, {R4-R7,R11,LR}
.text:00001CAC SUB SP, SP, #8
.text:00001CB0 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1CC0)
.text:00001CB4 LDR R5, =(unk_6290 - 0x5FBC)
.text:00001CB8 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001CBC ADD R0, R5, R0 ; unk_6290
.text:00001CC0 LDRB R0, [R0,#(isDlsymInited - 0x6290)]
.text:00001CC4 CMP R0, #0
.text:00001CC8 BNE loc_1D0C
.text:00001CCC MOV R1, #4
.text:00001CD0 MOV R0, #0xC5
.text:00001CD4 STR R1, [SP,#0x20+var_20]
.text:00001CD8 STR R0, [SP,#0x20+var_1C]
.text:00001CDC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1CEC)
.text:00001CE0 LDR R1, =(encrpty_dlsym - 0x5FBC)
.text:00001CE4 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001CE8 ADD R2, R1, R0
.text:00001CEC LDR R1, =(a9hbb - 0x5FBC)
.text:00001CF0 ADD R4, R5, R0 ; unk_6290
.text:00001CF4 ADD R3, R1, R0 ; dlsym Decryption key
.text:00001CF8 ADD R0, R4, #0x47
.text:00001CFC MOV R1, #6
.text:00001D00 BL DecrptionIATTable ;Decryption algorithm 1
.text:00001D04 MOV R0, #1
.text:00001D08 STRB R0, [R4,#(isDlsymInited - 0x6290)]
.text:00001D0C
.text:00001D0C loc_1D0C ; CODE XREF: initIATTable+20j
.text:00001D0C LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1D18)
.text:00001D10 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001D14 ADD R6, R5, R0 ; unk_6290
.text:00001D18 MOV R0, #0xFFFFFFFF ; handle
.text:00001D1C ADD R1, R6, #0x47 ; name
.text:00001D20 BL dlsym_0
.text:00001D24 MOV R4, R0 ; RO by dlsym Code address
.text:00001D28 LDRB R0, [R6,#(isGetpidInited - 0x6290)]
.text:00001D2C CMP R0, #0
.text:00001D30 BNE loc_1D74
.text:00001D34 MOV R1, #2
.text:00001D38 MOV R0, #0xD5
.text:00001D3C STR R1, [SP,#0x20+var_20]
.text:00001D40 STR R0, [SP,#0x20+var_1C]
.text:00001D44 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1D54)
.text:00001D48 LDR R1, =(unk_448B - 0x5FBC)
.text:00001D4C ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001D50 ADD R2, R1, R0
.text:00001D54 LDR R1, =(aM7 - 0x5FBC)
.text:00001D58 ADD R6, R5, R0 ; unk_6290
.text:00001D5C ADD R3, R1, R0 ; getpid Decryption key
.text:00001D60 ADD R0, R6, #0x5F
.text:00001D64 MOV R1, #7
.text:00001D68 BL DecrptionIATTable
.text:00001D6C MOV R0, #1
.text:00001D70 STRB R0, [R6,#(isGetpidInited - 0x6290)]
.text:00001D74
.text:00001D74 loc_1D74 ; CODE XREF: initIATTable+88j
.text:00001D74 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1D80)
.text:00001D78 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001D7C ADD R6, R5, R0 ; unk_6290
.text:00001D80 MOV R0, #0xFFFFFFFF
.text:00001D84 ADD R1, R6, #0x5F
.text:00001D88 BLX R4 ; _GLOBAL_OFFSET_TABLE_
.text:00001D8C STR R0, [R6,#(getpid_IAT - 0x6290)]
.text:00001D90 LDRB R0, [R6,#(isSprintfInited - 0x6290)]
.text:00001D94 CMP R0, #0
.text:00001D98 BNE loc_1DDC
.text:00001D9C MOV R1, #4
.text:00001DA0 MOV R0, #0xE9
.text:00001DA4 STR R1, [SP,#0x20+var_20]
.text:00001DA8 STR R0, [SP,#0x20+var_1C]
.text:00001DAC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1DBC)
.text:00001DB0 LDR R1, =(unk_44F3 - 0x5FBC)
.text:00001DB4 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001DB8 ADD R2, R1, R0
.text:00001DBC LDR R1, =(aLnat - 0x5FBC)
.text:00001DC0 ADD R6, R5, R0 ; unk_6290
.text:00001DC4 ADD R3, R1, R0 ; Decrypt sprintf Of key
.text:00001DC8 ADD R0, R6, #0x7C
.text:00001DCC MOV R1, #8
.text:00001DD0 BL DecrptionIATTable1 Decryption algorithm2
.text:00001DD4 MOV R0, #1
.text:00001DD8 STRB R0, [R6,#(isSprintfInited - 0x6290)]
.text:00001DDC
.text:00001DDC loc_1DDC ; CODE XREF: initIATTable+F0j
.text:00001DDC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1DE8)
.text:00001DE0 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001DE4 ADD R6, R5, R0 ; unk_6290
.text:00001DE8 MOV R0, #0xFFFFFFFF
.text:00001DEC ADD R1, R6, #0x7C
.text:00001DF0 BLX R4 ; _GLOBAL_OFFSET_TABLE_
.text:00001DF4 STR R0, [R6,#(sprintf_IAT - 0x6290)]
.text:00001DF8 LDRB R0, [R6,#(isFopenInited - 0x6290)]
.text:00001DFC CMP R0, #0
.text:00001E00 BNE loc_1E44
.text:00001E04 MOV R1, #4
.text:00001E08 MOV R0, #0xE7
.text:00001E0C STR R1, [SP,#0x20+var_20]
.text:00001E10 STR R0, [SP,#0x20+var_1C]
.text:00001E14 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1E24)
.text:00001E18 LDR R1, =(a0WE - 0x5FBC)
.text:00001E1C ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001E20 ADD R2, R1, R0 ; "0 A kind of w Chung"
.text:00001E24 LDR R1, =(aCoxt - 0x5FBC)
.text:00001E28 ADD R6, R5, R0 ; unk_6290
.text:00001E2C ADD R3, R1, R0 ; Decrypt fopen Of key
.text:00001E30 ADD R0, R6, #0x4D
.text:00001E34 MOV R1, #6
.text:00001E38 BL DecrptionIATTable1
.text:00001E3C MOV R0, #1
.text:00001E40 STRB R0, [R6,#(isFopenInited - 0x6290)]
.text:00001E44
.text:00001E44 loc_1E44 ; CODE XREF: initIATTable+158j
.text:00001E44 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1E50)
.text:00001E48 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001E4C ADD R6, R5, R0 ; unk_6290
.text:00001E50 MOV R0, #0xFFFFFFFF
.text:00001E54 ADD R1, R6, #0x4D
.text:00001E58 BLX R4 ; _GLOBAL_OFFSET_TABLE_
.text:00001E5C STR R0, [R6,#(fopen_IAT - 0x6290)]
.text:00001E60 LDRB R0, [R6,#(isFgetsdInited - 0x6290)]
.text:00001E64 CMP R0, #0
.text:00001E68 BNE loc_1EA4
.text:00001E6C MOV R6, #1
.text:00001E70 MOV R0, #3
.text:00001E74 LDR R1, =(aIU - 0x5FBC)
.text:00001E78 STMEA SP, {R0,R6}
.text:00001E7C LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1E88)
.text:00001E80 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001E84 ADD R2, R1, R0 ; "┑Fu"
.text:00001E88 LDR R1, =(aBmt - 0x5FBC)
.text:00001E8C ADD R7, R5, R0 ; unk_6290
.text:00001E90 ADD R3, R1, R0 ; Decrypt fgets Of key
.text:00001E94 ADD R0, R7, #0x53
.text:00001E98 MOV R1, #6
.text:00001E9C BL DecrptionIATTable
.text:00001EA0 STRB R6, [R7,#(isFgetsdInited - 0x6290)]
......
.text:000021D8 ADD SP, SP, #8
.text:000021DC LDMFD SP!, {R4-R7,R11,PC}
The contents of the get table after the execution of the appeal code are as follows:
After the previous preparations have been completed, pthread_create() is called, and the body of the function is in ThreadCallback.
The assembly code restored here in the previous file is a while loop, one calling the Anit Deubging code, and the other sleep ing (3) with threads dormant for three seconds.
.text:000016A4 ThreadCallback ; DATA XREF: JNI_OnLoad+A8o
.text:000016A4 ; .text:off_1CA4o
.text:000016A4 STMFD SP!, {R4,LR}
.text:000016A8 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x16B8)
.text:000016AC LDR R1, =(unk_6290 - 0x5FBC)
.text:000016B0 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:000016B4 ADD R4, R1, R0 ; unk_6290
.text:000016B8
.text:000016B8 loc_16B8 ; CODE XREF: ThreadCallback+24j
.text:000016B8 BL AnitDeubging
.text:000016BC LDR R1, [R4,#(sleep_IAT - 0x6290)]
.text:000016C0 MOV R0, #3
.text:000016C4 BLX R1 ; call sleep(3),Sleep for 3 seconds
.text:000016C8 B loc_16B8
Thread function c code restore
while(true){
AnitDeubging();
sleep(3);//Call function
}
Next is the point. We're about to unravel the anti-debugging secret.
Main work:
1,fopen("/proc/pid/status")
2. Loop fgets() to read the file content
3. Call strstr to locate "TracerPid" and get the value of the following TracerPid
4. TracerPid is 0, which means that the program has not been debugged. If it is larger than 1, it means that the process is attached.
5. When TracerPid is not 0, kill (my_pid) is executed, and the program exits.
Debugger Detection Business Logic 1
Call getpid api to get the process id of the current app, and then determine whether "/ proc/%d/status" has been decrypted or not, then call the decryption function to decrypt dynamically, and set the decrypted flag bit.
.text:0000130C STMFD SP!, {R4-R11,LR}
.text:00001310 SUB SP, SP, #0x324
.text:00001314 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1328) ; Dynamic debugging becomes 0 xF3CA6328
.text:00001318 MOV R1, #0x64
.text:0000131C MOV R2, #0
.text:00001320 ADD R4, PC, R0 ; _GLOBAL_OFFSET_TABLE_ ; got One of the tables"Head address"
.text:00001324 LDR R0, =(__stack_chk_guard_ptr - 0x5FBC)
.text:00001328 LDR R0, [R0,R4] ; __stack_chk_guard
.text:0000132C LDR R0, [R0]
.text:00001330 STR R0, [SP,#0x348+checkStack]; store the content pointed to by chk_guard in the current stack
.text:00001334 ADD R0, SP, #0x348+lpstrArry
.text:00001338 BL __aeabi_memset_0 ; call memset Initialize 100-size stack space
.text:0000133C LDR R7, =(unk_6290 - 0x5FBC)
.text:00001340 ADD R5, R7, R4 ; unk_6290
.text:00001344 LDR R0, [R5,#(getpid_IAT-0x6290)]; dynamic debugging found that this is the address of getpid (import table 0xF7010D1B)
.text:00001348 BLX R0 ; call getpid,Returning to the current process pid
.text:0000134C MOV R8, R0
.text:00001350 LDR R4, [R5,#(sprintf_IAT - 0x6290)] ; sprintf(0xF703E34B)
.text:00001354 LDRB R0, [R5,#(byte_635B - 0x6290)]
.text:00001358 CMP R0, #0; whether the content of byte_635b is 1
.text:0000135C BNE loc_13A0 ; if(byte_635b == 0){
.text:0000135C ; }
.text:00001360 MOV R1, #4
.text:00001364 MOV R0, #0x57
.text:00001368 STR R1, [SP,#0x348+local1]
.text:0000136C STR R0, [SP,#0x348+local2]
.text:00001370 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1380)
.text:00001374 LDR R1, =(dword_4550 - 0x5FBC)
.text:00001378 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:0000137C ADD R2, R1, R0 ; dword_4550
.text:00001380 LDR R1, =(aSL - 0x5FBC)
.text:00001384 ADD R5, R7, R0 ; unk_6290
.text:00001388 ADD R3, R1, R0 ; "s!#L"
.text:0000138C ADD R0, R5, #0xB9
.text:00001390 MOV R1, #0x10
.text:00001394 BL DecrptionIATTable1 ; Decrypted string"/proc/%d/status"
.text:00001398 MOV R0, #1; Set the global variable byte_635b flag bit to 1
.text:0000139C STRB R0, [R5,#(byte_635B - 0x6290)]
Debugger Detection Business Logic 2
Call sprintf("/proc/%d/status", PID) to construct the full path string of the status file of the current app process. Then decrypt
"TracerPid" string and set the decrypted flag bit
.text:000013A0 loc_13A0 ; CODE XREF: AnitDeubging+50j
.text:000013A0 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x13B0)
.text:000013A4 MOV R2, R8
.text:000013A8 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:000013AC ADD R6, R7, R0 ; unk_6290
.text:000013B0 ADD R0, SP, #0x348+lpstrArry
.text:000013B4 ADD R1, R6, #0xB9
.text:000013B8 BLX R4 ; call sprintf(lpstrArry,"/proc/%d/status",r2)
.text:000013BC LDR R5, [R6,#(fopen_IAT - 0x6290)]
.text:000013C0 LDRB R0, [R6,#(byte_635C - 0x6290)]
.text:000013C4 CMP R0, #0
.text:000013C8 BNE loc_1404
.text:000013CC MOV R6, #1
.text:000013D0 MOV R0, #0
.text:000013D4 LDR R1, =(unk_454A - 0x5FBC)
.text:000013D8 STMEA SP, {R0,R6}
.text:000013DC LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x13E8)
.text:000013E0 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:000013E4 ADD R2, R1, R0 ; unk_454A
.text:000013E8 LDR R1, =(unk_44FC - 0x5FBC)
.text:000013EC ADD R4, R7, R0 ; unk_6290
.text:000013F0 ADD R3, R1, R0 ; unk_44FC
.text:000013F4 MOV R0, R4
.text:000013F8 MOV R1, #2
.text:000013FC BL DecrptionIATTable2 ; Decrypt TracerPid Character string
.text:00001400 STRB R6, [R4,#(byte_635C - 0x6290)]
.text:00001404
.text:00001404 loc_1404
Debugger Detection Business Logic 3
Call fopen to open the "/proc/34352/status" file and read the content of 0x200 size.
.text:00001404 loc_1404 ; CODE XREF: AnitDeubging+BCj
.text:00001404 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1414)
.text:00001408 STR R8, [SP,#0x348+var_338]
.text:0000140C ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001410 ADD R4, R7, R0 ; unk_6290
.text:00001414 ADD R0, SP, #0x348+lpstrArry
.text:00001418 MOV R1, R4
.text:0000141C BLX R5 ; fopen("/proc/34352/status")
.text:00001420 ADD R6, SP, #0x348+var_28C
.text:00001424 MOV R5, R0 ; Function returns results
.text:00001428 MOV R1, #0x200
.text:0000142C MOV R2, #0
.text:00001430 MOV R0, R6
.text:00001434 STR R5, [SP,#0x348+statusFileFd]
.text:00001438 BL __aeabi_memset_0 ; memset(local_28c,0x200,0);It feels like this should be memset(local_28c,0,0x200)Only then
.text:0000143C LDR R3, [R4,#(fgets_IAT - 0x6290)]
.text:00001440 MOV R0, R6
.text:00001444 MOV R1, #0x200
.text:00001448 MOV R2, R5
.text:0000144C
.text:0000144C fgets__ ; fgets
.text:0000144C BLX R3
.text:00001450 MOV R6, R7 ; r6 = unk_6290
.text:00001454 CMP R0, #0; whether the comparison result is 0
.text:00001458 BEQ loc_161C ; Jumping from the point of view, not jumping executes a lot of code, you have to suspect that this is the key point.
Debugger Detection Business Logic 4
Loop call fgets to read the status file content, then call strstr("Name:.yaotong.crackme", "TracerPid") to find the substring, if found each time, continue to read the status file content until the end of the file. If TracerPid is found, the process ID in "TracerPid: 13654" is taken out, which is actually the ID of. / android_server process. Determine whether the process ID is greater than or equal to 1, and if it is greater than 1, walk out of the program process.
.text:000014F8 loc_14F8 ; CODE XREF: AnitDeubging+2ECj
.text:000014F8 LDR R5, [R8,#(strstr_IAT - 0x6290)]
.text:000014FC LDRB R0, [R8,#(byte_635D - 0x6290)]
.text:00001500 CMP R0, #0
.text:00001504 BNE loc_154C ; Decrypt"%s,%d"String, if decrypted, skips
.text:00001508 MOV R0, #2
.text:0000150C LDR R2, [SP,#0x348+var_324]
.text:00001510 LDR R3, [SP,#0x348+var_328]
.text:00001514 MOV R11, R4
.text:00001518 MOV R4, R6
.text:0000151C MOV R1, #0xA
.text:00001520 STR R0, [SP,#0x348+local1]
.text:00001524 MOV R0, #0x9D
.text:00001528 STR R0, [SP,#0x348+local2]
.text:0000152C LDR R0, [SP,#0x348+var_320]
.text:00001530 ADD R6, R4, R0
.text:00001534 ADD R0, R6, #0x95
.text:00001538 BL DecrptionIATTable
.text:0000153C MOV R0, #1
.text:00001540 STRB R0, [R6,#0xCD]
.text:00001544 MOV R6, R4
.text:00001548 MOV R4, R11
.text:0000154C
.text:0000154C loc_154C ; CODE XREF: AnitDeubging+1F8j
.text:0000154C MOV R0, R9
.text:00001550 MOV R1, R7
.text:00001554 BLX R5 ; example strstr("Name:.yaotong.crackme","TracerPid")
.text:00001558 CMP R0, #0 ; if(r0 != 0){}
.text:0000155C BEQ loc_15DC ; lookup TracerPid Character string
.text:00001560 MOV R0, R4
.text:00001564 MOV R1, #0x80
.text:00001568 MOV R2, #0
.text:0000156C BL __aeabi_memset_0
.text:00001570 MOV R0, #0
.text:00001574 STR R0, [SP,#0x348+local_key]
.text:00001578 LDR R11, [R10,#(sscanf_IAT - 0x6290)]
.text:0000157C LDRB R0, [R10,#(byte_635E - 0x6290)]
.text:00001580 CMP R0, #0
.text:00001584 BNE loc_15BC
.text:00001588 MOV R0, #3
.text:0000158C LDR R2, [SP,#0x348+var_330]
.text:00001590 LDR R3, [SP,#0x348+var_334]
.text:00001594 MOV R1, #6
.text:00001598 STR R0, [SP,#0x348+local1]
.text:0000159C MOV R0, #0x93
.text:000015A0 STR R0, [SP,#0x348+local2]
.text:000015A4 LDR R0, [SP,#0x348+var_32C]
.text:000015A8 ADD R5, R6, R0
.text:000015AC ADD R0, R5, #0x41
.text:000015B0 BL DecrptionIATTable1 ; Decrypted string
.text:000015B4 MOV R0, #1
.text:000015B8 STRB R0, [R5,#0xCE]
.text:000015BC
.text:000015BC loc_15BC ; CODE XREF: AnitDeubging+278j
.text:000015BC LDR R1, [SP,#0x348+var_31C]
.text:000015C0 MOV R0, R9
.text:000015C4 MOV R2, R4
.text:000015C8 ADD R3, SP, #0x348+local_key
.text:000015CC BLX R11 ; 3 A parametric function
.text:000015D0 LDR R0, [SP,#0x348+local_key]
.text:000015D4 CMP R0, #1 ; TracerPid :(./android_server)
.text:000015D8 BGE loc_1600 ; TracerPid >= 1 Note that it is being debugged
.text:000015DC
.text:000015DC loc_15DC ; CODE XREF: AnitDeubging+250j
.text:000015DC LDR R0, [SP,#0x348 + fgetsOffsetAddr]; R0 < 1 continues
.text:000015E0 LDR R2, [SP,#0x348+statusFileFd]
.text:000015E4 MOV R1, #0x200
.text:000015E8 LDR R3, [R0,#0x10]
.text:000015EC MOV R0, R9 ; szBuffer
.text:000015F0 BLX R3 ; fgets()
.text:000015F4 CMP R0, #0; The result is not equal to 0 to continue the cycle, otherwise jump out of the cycle.
.text:000015F8 BNE loc_14F8
.text:000015FC B loc_161C
Debugger Detection Business Logic 5
If the value of TracerPid is greater than or equal to 1, execute kill(pid), exit your own program, and if it is equal to 0, the process will normally end and wait for the next detection.
.text:00001600 loc_1600 ; CODE XREF: AnitDeubging+2CCj
.text:00001600 LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x1610)
.text:00001604 MOV R1, #9
.text:00001608 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:0000160C ADD R0, R6, R0
.text:00001610 LDR R2, [R0,#gotOffsetOfKill]
.text:00001614 LDR R0, [SP,#0x348+var_338]
.text:00001618 BLX R2 ; __imp___stack_chk_fail ; What's actually called is kill(pid)function
.text:0000161C ; ---------------------------------------------------------------------------
.text:0000161C
.text:0000161C loc_161C ; CODE XREF: AnitDeubging+14Cj
.text:0000161C ; AnitDeubging+2F0j
.text:0000161C LDR R0, =(_GLOBAL_OFFSET_TABLE_ - 0x162C)
.text:00001620 LDR R1, =(__stack_chk_guard_ptr - 0x5FBC)
.text:00001624 ADD R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_
.text:00001628 LDR R0, [R1,R0] ; __stack_chk_guard
.text:0000162C LDR R0, [R0]
.text:00001630 LDR R1, [SP,#0x348+checkStack]
.text:00001634 SUBS R0, R0, R1
.text:00001638 ADDEQ SP, SP, #0x324
.text:0000163C LDMEQFD SP!, {R4-R11,PC}
.text:00001640 BL __stack_chk_fail_0
When the program is debugging, let's take a look at the status file of crackme.
Note line 6 of the figure, TracerPid: 16364
Next, verify which process 16364 is.
Line 3 of the figure, PID 16364, is the android_server process.
Summary of Back-Debugging Technology
Crame reads the value of "TracerPid" in the "/proc/self/status" file through a loop. If the value is greater than 1, the process is added. That is, there is a program debugging the app, and then killing (self_pid) is used to send a kill signal to the system so that the system can terminate the process of app.
Technical summary
Seen from the whole so library code, crackme's security programming idea is well applied. Strings are encrypted and saved, and decrypted only when used. This static analysis brings some difficulties. There are not only one decryption algorithm, but also the decryption algorithm, which feels confused. It is not difficult to guess that the decryption code is also encrypted and saved, and then decrypted when it is running. I will not analyze it here. Interested students can analyze it.