crackme例子2

样本在这里插入图片描述

jadx

在这里插入图片描述

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")

dump后文件拖入Ida,正常看来这是解密后的函数了
在这里插入图片描述

伪代码如下

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大杀器

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 [安全攻防进阶篇] 中,有关于逆向分析的教程可以帮助你了解如何使用OllyDbg逆向CrackMe程序。 OllyDbg是一种常用的逆向工具,可以用于分析和修改程序的执行流程和内存。使用内存断点和普通断点,可以在程序执行过程中捕获关键的代码位置,帮助我们找到CrackMe程序的OEP(Original Entry Point),即程序的入口点。 在 [安全攻防进阶篇] 中还有关于逆向分析两个CrackMe程序的详细教程,包括逆向分析和源码还原的步骤。这些教程将帮助你理解逆向分析的基本概念和技巧,提升你的安全能力。 如果你想深入学习如何使用OllyDbg逆向CrackMe程序,可以参考这些教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [[安全攻防进阶篇] 六.逆向分析之OllyDbg逆向CrackMe01-02及加壳判断](https://blog.csdn.net/Eastmount/article/details/107777190)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [逆向crackme之ESp定律脱壳](https://blog.csdn.net/qq_58970968/article/details/125357834)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骇客之技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值