clacSnFuntion jni函数,ida分析
关键位置函数一片红色,可能有动态加解密
如果不分析具体解密算法,可内存dump解密后整个so
frida如下:
function dump_so(so_name) {
Java.perform(function () {
var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
var dir = currentApplication.getApplicationContext().getFilesDir().getPath();
var libso = Process.getModuleByName(so_name);
console.log("[name]:", libso.name);
console.log("[base]:", libso.base);
console.log("[size]:", ptr(libso.size));
console.log("[path]:", libso.path);
var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";
var file_handle = new File(file_path, "wb");
if (file_handle && file_handle != null) {
Memory.protect(ptr(libso.base), libso.size, 'rwx');
var libso_buffer = ptr(libso.base).readByteArray(libso.size);
file_handle.write(libso_buffer);
file_handle.flush();
file_handle.close();
console.log("[dump]:", file_path);
}
});
}
dump_so("libclacSn.so")
伪代码如下
int __fastcall sub_21B4(const char *imei, const char *userName, const char *sn)
{
int v3; // r4
int v4; // lr
int v5; // r11
int v6; // r9
void *v8; // r0
void *v9; // r4
int result; // r0
void (__fastcall *v11)(int *); // r11
int userName_len2; // r4
int *v13; // r6
int i; // r3
int v15; // r0
int *v16; // r5
unsigned int v17; // r2
int v18; // r2
char v19; // r2
int j; // r3
char *v21; // r5
int k; // r4
int v23; // r2
int v24; // r3
signed int userName_len; // [sp+10h] [bp-44h]
unsigned int v28; // [sp+10h] [bp-44h]
signed int imei_len; // [sp+14h] [bp-40h]
int v30[6]; // [sp+18h] [bp-3Ch]
int v31[6]; // [sp+30h] [bp-24h] BYREF
char name[4]; // [sp+48h] [bp-Ch] BYREF
int v33; // [sp+4Ch] [bp-8h]
int v34; // [sp+50h] [bp-4h] BYREF
int v35[64]; // [sp+54h] [bp+0h] BYREF
int v36[4]; // [sp+154h] [bp+100h] BYREF
int v37[18]; // [sp+164h] [bp+110h] BYREF
int v38[5]; // [sp+1ACh] [bp+158h] BYREF
int v39[5]; // [sp+1C0h] [bp+16Ch]
char v40[8]; // [sp+1D4h] [bp+180h] BYREF
int v41; // [sp+1DCh] [bp+188h]
v3 = 0;
v4 = *(_DWORD *)off_4F24;
v30[5] = 0;
v31[5] = 0;
v30[1] = 523322177;
v31[1] = 272376371;
v30[2] = 536953137;
v31[2] = 258025531;
v30[3] = 1346515761;
v31[3] = 320878139;
v30[4] = 1135118;
v5 = 1074270993;
v6 = 863068190;
v41 = v4;
v31[4] = 6168864;
*(_DWORD *)name = 1346109522;
v31[0] = 1074270993;
v30[0] = 863068190;
v33 = 0;
memset(v35, 0, sizeof(v35));
v39[1] = 0;
v39[2] = 0;
v39[3] = 0;
v39[4] = 0;
v39[0] = 0;
imei_len = strlen(imei);
userName_len = strlen(userName);
while ( 1 )
{
v31[v3++] = v6 + v5;
if ( v3 == 6 )
break;
v5 = v31[v3];
v6 = v30[v3];
}
*(_DWORD *)name = 1701669236;
v8 = dlopen((const char *)v31, 0);
v9 = v8;
if ( !v8 )
return -1;
v11 = (void (__fastcall *)(int *))dlsym(v8, name);
dlclose(v9);
v11(&v34);
if ( strlen(sn) != 16 )
goto LABEL_7;
userName_len2 = userName_len;
if ( userName_len >= imei_len )
userName_len2 = imei_len;
v28 = v34 / 0x14u;
v13 = (int *)malloc(imei_len + 1);
memset(v13, 0, imei_len + 1);
v11(&v34);
*v13 ^= (v34 / 20) ^ v28;
strcpy((char *)v13, imei);
if ( userName_len2 > 0 )
{
for ( i = 0; i != userName_len2; ++i )
*((_BYTE *)v13 + i) ^= userName[i];
}
v11(&v34);
v15 = *v13;
v38[1] = 0;
v38[2] = 0;
v38[3] = 0;
*v13 = v15 ^ (v34 / 20) ^ v28;
v38[4] = 0;
v16 = v36;
v36[0] = 1732584193;
v36[1] = -271733879;
v36[2] = -1732584194;
v37[0] = 0;
v36[3] = 271733878;
v38[0] = 0;
v37[1] = 0;
sub_1B78(v36, v13, imei_len);
sub_1C64(v40, v37, 8);
v17 = ((unsigned int)v37[0] >> 3) & 0x3F;
v18 = v17 > 0x37 ? 120 - v17 : 56 - v17;
sub_1B78(v36, 24388, v18);
sub_1B78(v36, v40, 8);
sub_1C64(v38, v36, 16);
do
{
*(_BYTE *)v16 = 0;
v16 = (int *)((char *)v16 + 1);
}
while ( v16 != v38 );
v19 = 16;
for ( j = 0; j != 16; ++j )
*((_BYTE *)v39 + j) = v19++ ^ *((_BYTE *)v38 + j);
v21 = (char *)v35;
for ( k = 0; k != 16; ++k )
{
v23 = *((unsigned __int8 *)v39 + k);
v24 = k + 16;
sprintf(v21, "%02X", v23 ^ v24);
v21 += 2;
}
v11(&v34);
v35[0] ^= v28 ^ (v34 / 20);
free(v13);
if ( !memcmp(v35, sn, 0x10u) )
result = 1;
else
LABEL_7:
result = 0;
return result;
}
由于老app对运行环境有要求。
本机是安卓10,常见模拟器又没法动态调试arm,采取unidbg大杀器
package com.ucweb.crackme140522;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.hook.hookzz.HookEntryInfo;
import com.github.unidbg.hook.hookzz.HookZz;
import com.github.unidbg.hook.hookzz.IHookZz;
import com.github.unidbg.hook.hookzz.InstrumentCallback;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;
import com.sun.jna.Pointer;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
public MainActivity() {
emulator = AndroidEmulatorBuilder.for32Bit()
.setProcessName("com.ucweb.crackme140522")
.build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM();
vm.setVerbose(false);
vm.setJni(this);
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/armeabi/libclacSn.so"), false);
dm.callJNI_OnLoad(emulator);
}
public void destroy() throws IOException {
emulator.close();
}
public boolean clacSnFuntion(String imei, String user_name, String input_sn) {
String methodSign = "clacSnFuntion(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z";
DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);
return obj.callJniMethodBoolean(emulator, methodSign, imei, user_name, input_sn);
}
public void hook() {
Symbol memcmp = emulator.getMemory().findModule("libc.so").findSymbolByName("memcmp");
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.instrument(memcmp, new InstrumentCallback<RegisterContext>() {
@Override
public void dbiCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
Pointer calc_sn = ctx.getPointerArg(0);
Pointer input_sn = ctx.getPointerArg(1);
int size = ctx.getIntArg(2);
System.out.println("calc_sn=" + calc_sn.getString(0) + ", input_sn=" + input_sn.getString(0));
// 只需取前16位计算的值
}
});
}
public static void main(String[] args) throws Exception {
String imei = "358022025281637";
String user_name = "haikejishu";
String input_sn = "FEFAC64990C1224F";
MainActivity mainActivity = new MainActivity();
mainActivity.hook();
System.out.println(mainActivity.clacSnFuntion(imei, user_name, input_sn));
mainActivity.destroy();
}
}
crackme资源
分析算法
面试三题
解密idc脚本
auto start_addr = 0x4F44;
auto patch_addr = 0x21B4;
auto lenth = 0x414;
auto i=0;
for(i=0;i<lenth;i++)
{
PatchByte(patch_addr+i, Byte(start_addr+i)^0x55);
}