逆向学习crackme160题-003-Cruehead-CrackMe-3的 write up

简介: 逆向学习crackme160题-003-Cruehead-CrackMe-3的 write up

003-Cruehead-CrackMe-3的 write up

抄一百篇不如自己实践操作写一篇,尊重知识产权,写笔记辛苦,禁止转载!!

1. 执行程序测试

如上图,程序执行后什么也没有,就是一些字符串,猜测有一些内容是需要破解之后才能够显示出来。

2. 程序查壳

解释:程序无壳

3. 静态调试

  1. 首先将程序拖入32位IDA后先点击View(查看)——>Open subviews——>Strings,结果如下图:

    解释:可以看到有一些字符串是程序运行的时候没有显示出来的,这应该是需要破解之后才能显示的,猜测CRACKME3.KEY可能是一个文件名。
  2. 查看输入表,点击View——>Open subviews——>Imports,结果如下:

解释:这里只截屏来部分重要的API,并不是全部,但是可以猜测到这是和文件操作有关系。

详情:https://blog.csdn.net/jeanphorn/article/details/44982273
GreateFileA 创建或打开文件或I / O设备,返回值句柄(写的时候记得头文件: Fileapi.h)详情见https://blog.csdn.net/weixin_42810844/article/details/103246109
ReadFile   从文件指针指向的位置开始将数据读出到一个文件中
WriteFile     将数据写入一个文件
OpenFile    以不同方式打开文件的操作
  1. 可以用跟踪关键的字符串,或者是API函数,通过IDA的交叉引用,找到关键的主函数start。如果是流程图的形式,可以采用右键——>Text vie,以整篇形式观察加注释。如下图:

解释:可以知道程序的大致思路是需要打开一个包含注册码的文件,00401035文件存在则跳转,文件不存在则顺序执行,0040103C执行call调用的函数是拼接字符串,进入函数如下图:

解释:可见拼接的字符串是在CrackMe v3.0后面回车然后拼接“-Uncracked”,这是由于程序是由大端序模式存储的,所以数据高位在低位。

如果文件存在则跳转到00401043,开始读取文件内容并读取18个字符,保存到缓冲区402008,然后再来判断读取到的文件内字符串是不是18个字符,00401074的call调用00401311的函数进行

解密操作,如下图:

解释:解密时将把18个字符中的前14个字符每一个依次与“A~N"字符进行异或,所以是14次,然后将每次异或的结果储存到004020F9进行累加。最后回到第一张图,将累加出来的结果进行四个字节的异或,结果继续保存到了4020F9。

  1. 接下来的操作如下图:

注意重要知识点:SETZ AL //取标志寄存器中ZF的值, 放到AL中. SETNZ取得ZF值后, 取反, 再放到AL中.

解释:把校验结果保存在al里入栈了,接下来到后面还会进行一次检验。

  1. 然后经过一段窗口创建的操作之后,在进入消息循环之前,做了这样一个校验,校验文件内容是否正确,正确就弹框提示,正是通过刚刚push的al进行校验的

4. 动态调试

动态调试结合会让很多的数据看起来比较清晰。

  1. main函数,关节处加入了断电如下

5. 程序复现

注册码的检验是:

  1. 18个字符串中取出前14个字符依次分别与”A~N"进行异或运算
  2. 将每次异或出来的结果累加保存
  3. 最后累加的结果和0x123456再次进行异或
  4. 最后异或的结果和最后面四个字符比较。

注册机的生成思路是:

  1. 随便输入14个字符串,然后分别依次和“A~N”的结果进行异或
  2. 每次异或的结果累加保存起来,最后和0x123456异或
  3. 然后将最后异或出的结果拼接到14个字符后面,即可完成生成。
#include <stdio.h>
#include <windows.h>
#include <string.h>

int main()
{
  void generatekey(char key);  //声明函数
  char key[19] = { 0 };//储存用户输入的字符,做实际参数
  printf("enter you username: ");
  scanf("%s", key);
  generatekey(key);    //调用函数
  system("pause");
  return 0;
}
void generatekey(char key[19])
{
  char KEY[19] = { 0 };           //存储序列号
  int i = 0;          //充当字符串的下标
  int k = 0;          //充当循环计数
  char bl = 'A';        //用来解密的字符串
  unsigned int sum = 0;   //每次异或的累加值储存到这里
  unsigned char* tmp = { 0 };   //无符号的字符串指针初始化0
  strcpy(KEY, key);      //将用户输入的字符串复制到KEY
  do                    //循环解密
  {
    KEY[i] ^= bl;
    sum += KEY[i];
    i++;
    bl++;
    if (!KEY[i]) break;
  } while (bl!='O');
  sum ^= 0x12345678;    //累加值异或
  *(unsigned int*)&KEY[0xE] = sum;  //将前面异或出来的结果拼接到KEY的后4个字符
  for ( k = 0; k < 18; k++)     //循环遍历以两位十六进制数输出KEY
  {
    tmp = (unsigned char*)&KEY;
    printf("%02x ", tmp[k]);
  }
  printf("\nstrlen(tmp)=%d\n", strlen(tmp));//求输出字符串的实际长度(不包含/0)
  //由于前14个字符储存的是异或的结果,所以下面要把前14个字符逆向异或回原来的字符
  int j = 0xD;  //充当下标
  char al = 'N';//充当解密字符
  do
  {
    tmp[j] ^= al;
    j--; 
    al--;
    if (!tmp[j])break;
  } while (al!='@');
  for (k = 0; k < 18; k++)//循环遍历以两位十六进制数输出KEY
  {
    tmp = (unsigned char*)&KEY;
    printf("%02x ", tmp[k]);
  }
  printf("\nstrlen(tmp)=%d\n", strlen(tmp));//求输出字符串的实际长度(不包含/0)
  printf("KEY: %s", KEY);//以字符串的形式输出KEY
  HANDLE hFile = CreateFileA  //函数的返回值是一个句柄
  ( "CRACKME3.KEY", //要打开的文件名字
    GENERIC_ALL, //允许设备进行所有操作
    0, //不共享
    NULL, //指针
    CREATE_ALWAYS,        //总是创建文件
    //OPEN_ALWAYS, //如果文件不存在则创建它
    FILE_ATTRIBUTE_NORMAL, //默认属性
    NULL    //指定文件句柄
  );
  DWORD retNum = 0;
  WriteFile
  ( hFile, //文件句柄
    KEY, //要写入的数据
    sizeof(KEY), //要写入的字节数,结果应该是给了后面的取地址
    &retNum, //实际写入的字符串
    NULL  //OVERLAPPED 结构,一般设定为 NULL
  );
  CloseHandle(hFile); //关闭句柄
}


相关文章
|
2月前
|
算法 数据安全/隐私保护
逆向学习crackme160题-008-Afkayas.1 的 write up
逆向学习crackme160题-008-Afkayas.1 的 write up
22 1
|
2月前
|
编译器 C++
逆向学习crackme160题-002-abexcm5的write up
逆向学习crackme160题-002-abexcm5的write up
23 1
|
2月前
|
存储
逆向学习crackme160题-015-Brad Soblesky.1 的 write up
逆向学习crackme160题-015-Brad Soblesky.1 的 write up
35 1
|
2月前
|
算法 数据安全/隐私保护
逆向学习crackme160题-011-wocy.1 的 write up
逆向学习crackme160题-011-wocy.1 的 write up
16 1
|
2月前
|
算法 API 数据安全/隐私保护
逆向学习crackme160题-007-reg 的 write up
逆向学习crackme160题-007-reg 的 write up
44 2
|
2月前
|
API C++
逆向学习crackme160题-006-ArturDents-CrackMe#2 的 write up
逆向学习crackme160题-006-ArturDents-CrackMe#2 的 write up
25 0
|
2月前
|
算法 数据安全/隐私保护
逆向学习crackme160题-009-Boonz-KeygenMe#1 的 write up
逆向学习crackme160题-009-Boonz-KeygenMe#1 的 write up
15 0
|
2月前
|
算法 API
逆向学习crackme160题-014-Splish 的 write up
逆向学习crackme160题-014-Splish 的 write up
37 0
|
2月前
|
算法
逆向学习crackme160题-012-ACG-crcme1 的 write up
逆向学习crackme160题-012-ACG-crcme1 的 write up
17 0
|
2月前
逆向学习crackme160题-005-Andrnalin.1 的 write up
逆向学习crackme160题-005-Andrnalin.1 的 write up
14 0