梦旅意中人 发表于 2022-2-17 00:33

【2022】春节解题领红包之三——新手向

本帖最后由 梦旅意中人 于 2022-2-17 21:14 编辑

## 那年我找到了一个String,却以为抓住了整个Key。



### 如果说上一篇是动静分离,那么这一篇就是动静结合了,对于大佬而言可能只需要OD工具就调出最终的结果了,但对我来这种菜鸡来讲需要多个工具一起分析,再加上一个不太灵光的脑袋, 也是可以勉强一战的,推荐先阅读上一篇文章【2022】春节解题领红包之二——新手向 ( https://www.52pojie.cn/thread-1588722-1-1.html ) 其中的一些思路和操作会对这道题的分析有帮助,如果你能动手跟着做一下那最好不过了,Enjoy the Time!

### 工欲善其事,必先利其器
      
吾爱专用虚拟机2.0 ( https://www.52pojie.cn/thread-661779-1-1.html )

IDA7.5   ( https://www.aliyundrive.com/s/4yE1LbvctT5 )

### 查壳



### UPX壳,我们的老朋友,使用ESP定律即可,关于ESP定律脱壳详细操作可参考我之前文章 ( 2020春节红包之二———小白成长的血泪史https://www.52pojie.cn/thread-1101472-1-1.html ) 观看脱壳部分学习即可,此处不多赘述。

### 收集信息,需要我们的UID和最终的Key,随便输入,提示Error



## 动态追溯

### 将脱壳后的文件拖入OD,这里选择否



### 右键依次选择中文搜索引擎—>智能搜索,Ctrl+F 找我们的提示信息Error(按N寻找下一个匹配项),这里除了Error,Success,还有一串神秘疑似key的字符串



### 结合前几年的题目,开始我的偷懒猜想,可就是这个字符串,困了我整整一天



### 既然看到我们的Success,那就它对应的汇编代码,双击后回到我们的汇编页面,熟悉的jnz,熟悉的cmp,还是原来的配方,还是原来的味道



### 往上我们发现了两个call函数,在离的最近的下个断点(按F2或者双击汇编代码前区域),待会看看有没有什么发现,按F9运行程序后,输入测试的1和123456(假装自己的UID为1哈哈哈哈),F7进入断点,一通F8过后,手指都快按断了,却什么也没有发现



## 静态分析

### 于是决定使用IDA分析一波,将文件再拖入IDA中看看有什么发现,阿,很快啊,我们就找到Success了,然后发现它上方面的判断模块,F5将汇编代码转为伪代码,(使用Shift+F12调处字符串窗口,再搜索Success也是可以的)



### 这里的sub_401520函数就是决定我们成功或是失败的条件,这里要求它的返回值为1才能进入Success,点击sub_401520函数,进入它的内部看看



### 直接滑到底部发现result ,而result的结果又与v8的值有关,而v8的结果又与另外一个函数sub_403ED0有关,这搁这套娃呢这是。我们必须保证v8返回值为false(为0),才可以使result的值为1,我们在这里打上断点(双击),调试看看(这里不清楚的同学可以看我开头提到的前一篇文章)这里的if语句以及这个函数中很长的代码部分需要注意一下,我们后边会用到



### 运行后输入我们的测试数据1,123456后回车,在断点的地方停下来,显示这个页面不用担心,按F5将代码转为伪C代码



### 按F7进入函数内部,然后F8执行,如果没有思路的时候,可以把鼠标悬停变量上,或许会有意想不到的收获,这里的v3为0x21,16进制转十进制即 33,这会预示什么呢?



### 继续F8,这个V4变量显示一个String(字符串)



### 双击V4,找到它的源地址,并把这个String拿到,得到"flag{Happy_New_Year_52Pojie_2022}",字符串长度恰好为33 = (0x21),这就是答案吗?不,才刚刚开始,,,



### 继续向下分析,我们发现这个v6中存放的值是3,也就是我们输入的字符串"123"的长度,而接下来又看见我们熟悉的result 和memcmp函数了,前面提到需要保证返回值为0,才可以进入Success,据此我们可知Key的长度为33



### 解题的那天家里正好还来了客人,我顾不得那么那么多,在电脑前不肯放弃(大家千万别学我),因为看多了B站老冯的 鸡汤来喽 的视频,找到这个String的时候高兴的不得了,情不自禁的念叨着"这(解题)多是一件美事呀!"

### 但使用获得的"flag{Happy_New_Year_52Pojie_2022}"却显示不正确,场面一度十分尴尬。起初以为是UID问题,后来由改了正确的UID,然后还是不行,摸摸我的秀发,深深的陷入了沉思



## 再回OD

### 在次将程序拖入OD,使用现在已知的条件,一次又一次的F8分析尝试,一次又一次Error,心里的疑惑越来越大,到底哪里出问题了?后来突然看着自己记录的字符串,忽然想起很久以前了解过一丁点密码学知识,似乎是凯撒加密还是别的什么,用于字符的移位操做,如ABC—>DEF,那么这道题是不是也有这样加密的方法



### 结合之前在IDA中发现的memcmp函数,可知需要比较的字符串为"flag{Happy_New_Year_52Pojie_2022}",也就是说,并不是要输入这个String,而是需要我们输入的Key经过计算后得到这个String,这才是解题的关键,在OD中看到的很长的F8的过程,其实就是在对字符串进行运算,然后做比较在返回结果。根据OD中显示的字符串发现数字没有改变,也就是说这个Key的加密运算和我们的输入的字母有关系,那么大小写字母对应的值也不一样(在这里我甚至已经联想到ASCII码,但没找到规律),所以将26个字母大小写输入会得到运算后的关系,进而得到我们要找的答案。

### 使用OD载入程序,这里输入测试UID = 1, Key = "abcdefghijklmnopqrstuvwxyz"



### 在之前我们下过的断点处停下,然后F7再进入函数内部,距离Success很近的call函数



### 这里需要很多次F8,结合之前在IDA中获得的信息,这个函数内有一个if条件,而且这里有许多相似的代码块,滑动鼠标中键,并且观察一下右边的内容,可以看到会重复重复出**"flag{Happy_New_Year_52Pojie_2022}"**,找到最后一个"}"



### 再向下可以发现一些call函数,和jnz跳转,就近原则,在00401CCE 这个地址下断点,按F9直接运行到这个断点,再按F7进入函数



### 一路F8可以发现输入的"abcdefghijklmnopqrstuvwxyz" 变成了 "rajsbktcludmvenwfoxgpyhqzi",别忘了,这是UID = 1时获得的值



### 输入我自己的UID = "990855"和对应的key = "abcdefghijklmnopqrstuvwxyz",可以得到对应的真实Key = **"dshwlapetixmbqfujyncrgvkzo"**,类比得到大写的字母对应的内容。结合以上可知,这种加密更像是MD5的散列函数,即Y = H(UID)的关系,我们输入UID,可以得到对应的一个Y,再通过Y对我们输入的Key进行移位操作,使得它最终变成 "flag{Happy_New_Year_52Pojie_2022}"



### 通过上图可以得知我的UID计算后的字符对应关系,进而写出我的Key "oefv{Cfggr_Shd_Rhfu_52Gzqjh_2022}",完美



### 官方其实对UID做了限制,从IDA中可以看出 2000000 就会提示错误,而这个函数保证了每个人所生成的Key是不一样的,避免在活动结束前泄露答案,还有每天只允许提交三次保证了服务不受过多的错误请求而占用资源(没错,就是我因为错误点击的刷新导致卡掉了当天的提交机会,只得到第二天凌晨提交),提交获得的Key后,后台就会根据用户的UID和Key进行计算得到"flag{Happy_New_Year_52Pojie_2022}"后,返回成功给前台, 真是妙啊。

### 还有一点有些疑惑的地方就是在下面的if-else条件语句块中,IDA中看到的代码似乎相差不大,是否说明这段代码设计之初有冗余,可以取公有的部分封装优化。



### ~~此处应该有分析整个代码块的加密算法的,但因为我不仅菜,而且懒,所以没有了。~~
### 评论区有位大佬给出了解密的注册机算法源码,大家可以去围观学习一下。
### 关于第四和第五题,Andriod题目确实触及到我的盲区了,虽然发现了最终的答案就在so层,不过被混淆了,即使补了很多功课,也还是没有解出来,第五题说来惭愧,楼主本来是学Java的,自诩对web题目也应该会当能信手拈来,但是后来分析很久只拿到了ts文件,没有找到解密的key因此无法得出结果,实属遗憾。

### 本文是为给那些像楼主一样的小白选手一些学习的参考,能够帮助他们接触到一些相关的知识便足矣,能使他们得以动手实操学习之再好不过,我想论坛的初衷也在于此,这些内容也是源于论坛文章的学习,在解题过程中,我翻看了论坛之前历年的春节红包活动的WP文章,学习了许多大佬们的经验,相信在座聪明的各位也能得以成功。

DEATHTOUCH 发表于 2022-2-17 15:05

分析的不错,思路和楼主差不多,顺便发个我写的屑注册机吧{:301_971:}
关照一下401100,401080,401110,还有那个究极折磨的4011B0
C语言的,VS2019或者gcc都可以编译

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>

int CalcMulNum(int UID)
{
    int n, t, i, m;
    n = 0;
    // 401080
    t = UID % 12;
    if (t <= 5)
      n = 2 * t + 1;
    else
      n = 2 * t + 3;
    // 401110
    int arr = { 0 };
    i = 0;
    t = 26;
    arr = 1;
    arr = 1;
    int *p = &arr;
    do {
      p += 4;
      i++;
      m = t % n;
      p = *p;
      p = *(p - 1) - t / n * (*p);
      p = p;
      p = p - t / n * p;
      t = n;
      n = m;
    } while (m);
    i *= 4;
    int result = arr;
    if (result < 0)
      result += 26;
    return result;
}

void GenerateMap(char *Upper, char *Lower, int SubNum, int MulNum)
{
    char c;
    int i;
    for (i = 0; i < 26; i++) {
      c = MulNum * (i - SubNum) % 26 + 65; // 4011B0
      if (c < 65)
            c += 26;
      Upper = c;
    }
    for (i = 0; i < 26; i++) {
      c = MulNum * (i - SubNum) % 26 + 97; // 4011B0
      if (c < 97)
            c += 26;
      Lower = c;
    }
}

int main()
{
    const char TrueFlag[] = "flag{Happy_New_Year_52Pojie_2022}";
    int UID, MulNum, SubNum;
    char MapUpper = { 0 };
    char MapLower = { 0 };
    printf("Please Input your UID: ");
    scanf("%d", &UID);
    if (UID > 2000000 || UID < 0) {
      printf("Invalid UID, Try again.\n");
      return 0;
    }
    SubNum = UID % 25; // 401100
    MulNum = CalcMulNum(UID);
    printf("SubNum: %d\n", SubNum);
    printf("MulNum: %d\n", MulNum);
    GenerateMap(MapUpper, MapLower, SubNum, MulNum);
    printf("MapUpper: %s\n", MapUpper);
    printf("MapLower: %s\n", MapLower);
    char flag = { 0 };
    for (int i = 0; i < 34; i++) {
      char c = TrueFlag;
      if (c <= 'Z' && c >= 'A') {
            for (int j = 0; j < 26; j++)
                if (MapUpper == c) {
                  flag = 65 + j;
                  break;
                }
      } else if (c <= 'z' && c >= 'a') {
            for (int j = 0; j < 26; j++)
                if (MapLower == c) {
                  flag = 97 + j;
                  break;
                }
      } else
            flag = c;
    }
    printf("YourFlag: %s\n", flag);
}

梦旅意中人 发表于 2022-2-17 21:21

DEATHTOUCH 发表于 2022-2-17 15:05
分析的不错,思路和楼主差不多,顺便发个我写的屑注册机吧
关照一下401100,401080,401110, ...

你也太谦虚了的,注册机写出来真的很厉害的,感谢分享,回头好好研究下,顺带告诉大家评论有大佬给出算法了,呼叫他们一起过来学习。

seawaycao 发表于 2022-2-17 12:27

谢谢分享!辛苦了!非常适合我这样的小白。

Meiosis 发表于 2022-2-17 13:39

学习一个

YSLW 发表于 2022-2-17 14:26

健康很快就很快就会

Mansion 发表于 2022-2-17 14:29

收藏学习一下。

akcode 发表于 2022-2-17 14:37

收藏学习一下。

Hmily 发表于 2022-2-17 17:55

能不能把图片上传下本地,图床太慢了,半天打不开图片嘞。

yuntiger 发表于 2022-2-17 20:11

多谢楼主分享

雪色的夏天 发表于 2022-2-17 20:42

学习一下
页: [1] 2 3
查看完整版本: 【2022】春节解题领红包之三——新手向