吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2381|回复: 17
收起左侧

[CrackMe] C写的CM一枚,XP可跑

[复制链接]
Sweettea 发表于 2020-7-5 11:15
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 Sweettea 于 2021-4-26 19:44 编辑

CM一枚

控制台程序
只有唯一正确解
输入:长度16以内的字符串
输出:成功输出true,失败输出false

无壳,
无暗桩,
无反调试,
有混淆,
有花指令

支持系统:XP - WIN10

破解要求:
爆破,追码,还原算法均可,看各位大佬玩得开心就好






==============以下2020年7月7日 00:54:17编辑======================

感谢大佬们的热心分析!
CM算法是个修改了的base64

此CM经过两次混淆:
第一次是基于C源代码的混淆,控制流平坦,无膨胀和花指令
第二次是编译链接阶段基于汇编代码的混淆,对代码进行了随机膨胀,加入了代码片段之间的随机跳转和花指令


贴上第二次膨胀混淆前的CM可执行文件.




关键函数功能:
sub_4010D0:
unsigned int __stdcall MyStrlen1(const char *string);
递归实现的strlen

sub_4012B0:
char __stdcall Dec1(char value);
单字节解密函数,用于解密base64表和要输出的"true"&"false"字符串

sub_4013A0:
void __stdcall KC_base64_encode(char *pIn, char *pOut);
修改的base64加密函数

sub_402010:
void *__stdcall DecMemcpy(void *dest, const void *src, unsigned int count);
调用了sub_4012B0的memcpy函数

sub_402240:
void __stdcall DoCmp(char *szInput, int (__cdecl *pfnputs)(const char *));
核心验证函数入口


@solly逆向找出的爆破点2:
00404520     85D2                      test edx,edx                      ; test edx,edx
在第二次膨胀混淆前的文件中对应的地址是:
loc_402683:
movzx   edx, [ebp+var_2]
test    edx, edx
jz      short loc_402698




附上第二次混淆等价替换的模版文件:






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 1吾爱币 +6 热心值 +1 收起 理由
CrazyNut + 6 + 1 下次请带上成功截图

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

solly 发表于 2020-7-9 09:10
解码结果:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x
solly 发表于 2020-7-6 02:05
本帖最后由 solly 于 2020-7-6 02:08 编辑

暴破位置,以下地址改成 xor edx, edx 即可:
00401A17      33D2                 xor edx,edx
就是把变换后的输入码与"oPRofQ6uigRhpmwHcYQt"比较时,强行将每个字符比较结果变成相等。

免费评分

参与人数 1热心值 +1 收起 理由
Sweettea + 1 用心讨论,共获提升!

查看全部评分

小菜鸟一枚 发表于 2020-7-5 12:35
本帖最后由 小菜鸟一枚 于 2020-7-5 12:39 编辑

跑不出来,OD CTRL+A也不太好用,这就是混淆吗?一下子选中三行代码,请问楼主这是c/c加加写的吗,能不能请教一下这个混淆和花指令该怎么做,或者给个教程吧,谢谢!
[C] 纯文本查看 复制代码
int sub_401020()
{
  __int128 v1; // [sp+0h] [bp-1Ch]@1
  __int64 v2; // [sp+10h] [bp-Ch]@1
  int v3; // [sp+18h] [bp-4h]@1

  v3 = 0;
  v1 = 0i64;
  _mm_storel_epi64((__m128i *)&v2, 0i64);
  sub_401070((int)"Input:", 0);
  sub_4010A0("%16s", &v1);
  sub_40180B(&v1, sub_41A35B);
  return 0;
}


[C] 纯文本查看 复制代码
signed int __cdecl sub_41A35B(const char *a1)
{
  signed int result; // eax@2
  int v2; // eax@3
  signed int v3; // eax@4
  signed int v4; // edx@4
  _BYTE *v5; // esi@4
  _BYTE *v6; // eax@6
  int *v7; // [sp+0h] [bp-14h]@14
  const char **v8; // [sp+4h] [bp-10h]@14
  int *v9; // [sp+8h] [bp-Ch]@14
  unsigned int v10; // [sp+Ch] [bp-8h]@14
  int v11; // [sp+10h] [bp-4h]@3

  if ( a1 )
  {
    v2 = sub_41A1FC(1);
    v11 = v2;
    if ( (*(_DWORD *)(v2 + 12) >> 12) & 1 )
      goto LABEL_17;
    v3 = sub_42295B(v2);
    v4 = v3;
    v5 = &unk_4350F8;
    if ( v3 == -1 || v3 == -2 )
      v6 = &unk_4350F8;
    else
      v6 = (_BYTE *)(dword_435F18[v3 >> 6] + 48 * (v3 & 0x3F));
    if ( v6[41] )
      goto LABEL_18;
    if ( v4 != -1 && v4 != -2 )
      v5 = (_BYTE *)(dword_435F18[v4 >> 6] + 48 * (v4 & 0x3F));
    if ( v5[45] & 1 )
    {
LABEL_18:
      *(_DWORD *)sub_421F2E() = 22;
      sub_421E72();
      result = -1;
    }
    else
    {
LABEL_17:
      v10 = strlen(a1);
      v7 = &v11;
      v8 = &a1;
      v9 = (int *)&v10;
      result = sub_41A2D1(v11, &v7);
    }
  }
  else
  {
    *(_DWORD *)sub_421F2E() = 22;
    sub_421E72();
    result = -1;
  }
  return result;
}


函数里面调函数,学习了,里面的那个函数有一次参数*a1,用OD跑了下参数也是输入的字符串,里面那个函数两个地方返回-1,应该是错误跳转,LANLE 17可能是正确的流程,然后跟丢了,没什么好的思路

OD层层回溯,也只能看到在哪里把false入栈的
[Asm] 纯文本查看 复制代码
004274C0   .  F64408 28 01  test byte ptr ds:[eax+ecx+0x28],0x1
004274C5   .  75 15         jnz short CrackMe.004274DC
004274C7   .  E8 62AAFFFF   call CrackMe.00421F2E
004274CC   .  C700 09000000 mov dword ptr ds:[eax],0x9
004274D2   .  E8 44AAFFFF   call CrackMe.00421F1B
004274D7   .  8320 00       and dword ptr ds:[eax],0x0
004274DA   .  EB 14         jmp short CrackMe.004274F0
004274DC   >  FF75 10       push dword ptr ss:[ebp+0x10]    ;这是字符串false\r\n长度,为7
004274DF   .  FF75 0C       push dword ptr ss:[ebp+0xC]    ;这就是字符串false\r\n


解不开了
 楼主| Sweettea 发表于 2020-7-5 13:05
本帖最后由 Sweettea 于 2020-7-5 13:08 编辑
小菜鸟一枚 发表于 2020-7-5 12:35
跑不出来,OD CTRL+A也不太好用,这就是混淆吗?一下子选中三行代码,请问楼主这是c/c加加写的吗,能不能请 ...

sub_41A35B是c库函数puts,

sub_40180B(&v1, sub_41A35B);
这是将puts函数指针从参数传递进sub_40180B里面调用

咋和c库函数刚上了呢
小菜鸟一枚 发表于 2020-7-5 13:27
Sweettea 发表于 2020-7-5 13:05
sub_41A35B是c库函数puts,

sub_40180B(&v1, sub_41A35B);

[Asm] 纯文本查看 复制代码
00401029  |.  C745 FC 00000>mov [local.1],0x0
00401030  |.  68 60E14200   push CrackMe.0042E160                    ;  ASCII "Input:"
00401035  |.  0F1145 E4     movups dqword ptr ss:[ebp-0x1C],xmm0
00401039  |.  660fd645 f4   movq qword ptr ss:[ebp-0xc],xmm0
0040103E  |.  E8 2D000000   call CrackMe.00401070
00401043  |.  8D45 E4       lea eax,[local.7]
00401046  |.  50            push eax
00401047  |.  68 68E14200   push CrackMe.0042E168                    ;  ASCII "%16s"
0040104C  |.  E8 4F000000   call CrackMe.004010A0
00401051  |.  83C4 0C       add esp,0xC
00401054  |.  8D45 E4       lea eax,[local.7]
00401057  |.  68 5BA34100   push CrackMe.0041A35B
0040105C  |.  50            push eax
0040105D  |.  E8 A9070000   call CrackMe.0040180B



好吧,那我分析不出来了,我怎么调试都觉得0040104C 这个call是最大获取16个字符串,接下来只剩下sub_40180B这个call有问题,觉得只能分析它了
风扫春残雪 发表于 2020-7-5 14:45
花指令和各种跳转看得头疼。。。。感觉得写脚本去一遍,或者静态模拟真实指令的东西才能把sub_40180B搞清楚

印象比较深的大概有
1.
mov reg,addr
lea  reg,[reg + offset]
jmp reg

2.
call offset
offset:
add/sub [esp], idata
retn

好奇楼主是怎么写出来的……是用宏指令完成的吗?求分享,非常好奇
类似的东西在壳里见过。。。不过他们的实现方式基本都是自己调一个反汇编引擎,然后直接代码膨胀/等价混淆再塞进去这样
 楼主| Sweettea 发表于 2020-7-5 16:36
风扫春残雪 发表于 2020-7-5 14:45
花指令和各种跳转看得头疼。。。。感觉得写脚本去一遍,或者静态模拟真实指令的东西才能把sub_40180B搞清楚 ...

提供下比较简单的思路:
vs编译选项里设置生成.asm文件,编译
对生成的.asm文件进行逐行解析,等价替换
把一个函数内的汇编代码分成n个小片段
每个代码片段之间随机加入跳转代码
每个代码片段随机打乱顺序
ml.exe编译.asm文件
link.exe链接obj

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
二娃 + 2 + 1 谢谢@Thanks!

查看全部评分

风扫春残雪 发表于 2020-7-5 19:31
头晕。。。试了很多种方法,最后发现还是得还原回来。。。还是老老实实从下到上分析吧

5#的乱序是最简单的几个,拼好了这些以后还要把一些辣鸡代码给收缩回来。感觉是个大工程……先把乱序拼回来了,吃饭去了
记录几个比较常见的模式(目测至少有十几种模式)

412D36     40834d : mov dword ptr ss:[esp-0x4],edx
412D36     408351 : lea esp,dword ptr ss:[esp-0x4]
412D36     408473 : lea esp,dword ptr ss:[esp+0x8]
412D36     408477 : mov edx,dword ptr ss:[esp-0x4]


412D36     40847b : mov ecx,0x71F870
412D36     408480 : sub ecx,0x231ECD



412D36     4084dd : mov dword ptr ss:[esp-0x4],ebx
412D36     4084e1 : sub esp,0x4
412D36     4082f9 : pop ebx



412D36     408305 : mov dword ptr ss:[esp-0x4],edx
412D36     408309 : sub esp,0x4
412D36     4086b0 : pop edx

免费评分

参与人数 1吾爱币 +1 收起 理由
Sweettea + 1 用心讨论,共获提升!

查看全部评分

 楼主| Sweettea 发表于 2020-7-5 19:40
风扫春残雪 发表于 2020-7-5 19:31
头晕。。。试了很多种方法,最后发现还是得还原回来。。。还是老老实实从下到上分析吧

5#的乱序是最简单 ...
分析得不错。
代码经过膨胀,要还原回来的确是个大工程。膨胀方式大约有个二三十种。
调试观察找出规律,找到爆破点感觉差不多就OK了。要还原算法,个人感觉是有点难了。要追码的话,找到关键点后,密码学数学大佬应该可以推出正确注册码。
solly 发表于 2020-7-6 12:38
本帖最后由 solly 于 2020-7-6 17:59 编辑

暴破2:
00404520     85D2                      test edx,edx                      ; test edx,edx
00404522     0F84 69040000      je CrackMe.00404991


把 je 指令 NOP 掉,这里是字符串比较结果的检查,跳转则显示 false,不跳转则显示 true。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-27 15:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表