吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8966|回复: 74
收起左侧

[CTF] 学破解第132天,《攻防世界reverse练习区Replace》学习

  [复制链接]
小菜鸟一枚 发表于 2020-11-28 21:30
本帖最后由 小菜鸟一枚 于 2020-11-28 21:34 编辑

学破解第132天,《攻防世界reverse练习区Replace》学习

前言:
  从小学到大专(计算机网络技术专业),玩过去的,所以学习成绩惨不忍睹,什么证书也没考,直到找不到工作才后悔,不知道怎么办才好。

  2017年12月16日,通过19元注册码注册论坛账号,开始做伸手党,潜水一年多,上来就是找软件。(拿论坛高大上的软件出去装X)

  2018年8月某一天,报名了华中科技大学网络教育本科(计算机科学与技术专业)2018级秋季。(开始提升学历)

  2019年6月17日,不愿再做小菜鸟一枚,开始零基础学习破解。(感谢小糊涂虫大哥在我刚开始学习脱壳时,录制视频解答我的问题)

  2020年7月7日,感谢H大对我的鼓励,拥有了第一篇获得优秀的文章。(接下来希望学习逆向,逆天改命)

  坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1278021-1-1.html
立帖为证!--------记录学习的点点滴滴

0x1下载文件

  1.是一个压缩包,下载解压出来后是一个exe程序。

  2.看到exe小菜鸟就放心,论坛的xp虚拟机太强大了,看小菜鸟如何用OD+lordPE+IRI脱UPX壳。

  3.小菜鸟将程序放进exe程序,发现居然打不开?小菜鸟告诉自己不慌,在win7真机环境下下载一个吾爱OD,运行程序居然自己退出了。

  4.小菜鸟只好直接打开这个程序,观察观察,发现就是要求输入正确的key,否则退出:
1.png

0x2新工具X32dbg的学习

  1.经过尝试,小菜鸟发现x32dbg工具能正常打开exe程序,虽然是一个陌生的工具,小菜鸟还是照着吾爱OD的操作,单步一次

013D7D20 | 60                       | pushad                                  |
013D7D21 | BE 00703D01              | mov esi,replace.13D7000                 |
013D7D26 | 8DBE 00A0FFFF            | lea edi,dword ptr ds:[esi-6000]         |
013D7D2C | 57                       | push edi                                |
013D7D2D | 83CD FF                  | or ebp,FFFFFFFF                         |
013D7D30 | EB 10                    | jmp replace.13D7D42                     |

  2.右键-》数据窗口中跟随,然而x32dbg工具中我找了半天,也没有找到数据窗口,最左下角是内存窗口,于是小菜鸟就跟随到内存1窗口,在内存1窗口中设置硬件断点,运行,取消硬件断点,单步几次到达OEP,vc++程序的入口特征就不用说了吧,就它了

013D13B0 | E8 DC020000              | call replace.13D1691                    |
013D13B5 | E9 91FEFFFF              | jmp replace.13D124B                     |
013D13BA | 55                       | push ebp                                |

  3.接下来怎么办呢?lordpe只能显示60个进程,看不到这个,没办法,小菜鸟又去下载了PEtool,都是英文,小菜鸟琢磨不透,最后只能试试x32dbg自带的scylla工具,还好,界面比较简单,能看懂,还能自己识别我找到的OEP,挺方便的,自动查找IAT,获取输入表,先dump,然后Fix Dump修复,程序脱壳成功,然后运行程序,程序异常了???
2.png

  4.这个问题打了小菜鸟一个措手不及,对x32dbg小菜鸟也不熟,完全不知道问题到底是出在哪了?UPX脱壳步骤应该也是没有问题的啊?

  5.小菜鸟没办法,百度c0000005异常也没找到什么有用的知识,说的都是兼容性什么的。异常偏移0000169f这个值引起了我的注意,想去x32dbg重新跑一下程序看看,这一看,小菜鸟发现程序的每次入口点都不一样:

01357D20 | 60                       | pushad                                  |
00DB7D20 | 60                       | pushad                                  |
013A7D20 | 60                       | pushad                                  |
00B77D20 | 60                       | pushad                                  |

  6.小菜鸟这下就知道是动态基址的问题的了,于是就去论坛搜索相关帖子,找到了用studype固定基址的办法(见文章末尾参考资料),固定基址后,程序正常运行。
3.png

0x3使用IDA分析程序

  1.程序已经被脱壳了,那就好办了,丢到IDA里面走起来,main函数已经被自动识别出来了,直接F5

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Buf; // [esp+4h] [ebp-2Ch]
  char Dst; // [esp+5h] [ebp-2Bh]

  Buf = 0;
  memset(&Dst, 0, 0x27u);
  printf("Welcome The System\nPlease Input Key:");
  gets_s(&Buf, 0x28u);
  if ( strlen(&Buf) - 35 <= 2 )
  {
    if ( sub_13D1090(&Buf) == 1 )
      printf("Well Done!\n");
    else
      printf("Your Wrong!\n");
  }
  return 0;
}

  2.跟着代码看一看,首先从键盘接收长度为40(0x28u)的字符串,然后计算字符串的长度减去35要小于等于2才会进入内层if,然后满足sub_13D1090(&Buf) == 1才是正确。

  3.进入sub_13D1090这个函数一探究竟,代码如下:

signed int __fastcall sub_13D1090(int a1, int a2)
{
  int v2; // ebx
  int v4; // edx
  char v5; // al
  int v6; // esi
  int v7; // edi
  char v8; // al
  int v9; // eax
  char v10; // cl
  int v11; // eax
  int v12; // ecx

  v2 = a1;
  if ( a2 != 35 )
    return -1;
  v4 = 0;
  while ( 1 )
  {
    v5 = *(_BYTE *)(v4 + v2);
    v6 = (v5 >> 4) % 16;
    v7 = (16 * v5 >> 4) % 16;
    v8 = byte_13D2150[2 * v4];
    if ( v8 < 48 || v8 > 57 )
      v9 = v8 - 87;
    else
      v9 = v8 - 48;
    v10 = byte_13D2151[2 * v4];
    v11 = 16 * v9;
    if ( v10 < 48 || v10 > 57 )
      v12 = v10 - 87;
    else
      v12 = v10 - 48;
    if ( (unsigned __int8)byte_13D21A0[16 * v6 + v7] != ((v11 + v12) ^ 0x19) )
      break;
    if ( ++v4 >= 35 )
      return 1;
  }
  return -1;
}

  4.还是继续使用我们的逆向思维,倒着看,要使if等于1,也就是必须return 1,要想return 1,v4要大于等于34,然后上面一堆的if else,小菜鸟已经懵圈了。

0x4换x32dbg动态调试

  1.首先,没得说,直接13D1090下断点,构造长度为35位的字符串12345678912345678912345678912345678,输入,运行:

013D1090 | 53                       | push ebx                                | ebx:"12345678912345678912345678912345678"
013D1091 | 8BD9                     | mov ebx,ecx                             | ebx:"12345678912345678912345678912345678", ecx:"12345678912345678912345678912345678"
013D1093 | 83FA 23                  | cmp edx,23                              | 23:'#'
013D1096 | 74 05                    | je 1.13D109D                            | 如果字符串长度不为35(0x23)直接返回-1

  2.看的小菜鸟头皮发麻,继续看,进入了while循环,根据前面的推导,必须return 1退出循环才行,那么v4显然就是控制循环退出的条件!再看看if ( v8 < 48 || v8 > 57 )这一句,我们判断是不是数字经常用的,如果是数字减去48,否则减去87,v8和v10是从两个数组中取数据。
既然如此,那么这两个数组的元素是什么呢?
直接x32dbg内存中就能看到:

byte ptr [edx*2+13D2150]=[013D2150 "2a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6"]=32 '2'
byte ptr [edx*2+13D2151]=[013D2151 "a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6"]=61 'a'

真的是看的清清楚楚,明明白白啊!

  3.再看v5 = v4 + v2,v2是ebx,看看x32dbg,ebx就是我们输入的字符串12345678912345678912345678912345678,接着就看v6和v7是在干啥了,右移4位对16取余, v7先乘16在右移四位对16取余,按我的理解就是v6取v5的低4位,v7取v5的高4位?

  4.接着也就是看最重要一句代码,跳向失败的条件:if ( (unsigned __int8)byte_13D21A0[16 * v6 + v7] != ((v11 + v12) ^ 0x19) ),每一次循环必须让这个等式成立。
13D21A0这个数组的值呢?
我姑且当二维数组来看,由于v7是对16取余,所以这个数组应该有16*16=256个元素,关键是这些元素的值是多少,真的是要人命啊,有没有技巧?

......
一小时后,小菜鸟通过16*0+0,一直计算到16*15+15,通过基址+偏移量终于得到了这256个元素,小菜鸟真是太傻了,百度一下就有(不知道这些大佬们怎么算的):
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16

  5.接下来就开始写代码爆破了:

// demo_ctf1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdlib.h"

int main()
{
        int v4 = 0, v5 = 0, v6 = 0, v7 = 0, v8 = 0, v9 = 0, v10 = 0, v11 = 0, v12 = 0;

        char arr1[] = "2a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6";
        char arr2[] = "a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6";

        char flag[36] = "";

        char arr3[] = {
                0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
                0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
                0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
                0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
                0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
                0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
                0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
                0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
                0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
                0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
                0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
                0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
                0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
                0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
                0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
                0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
        };

        while (1)//前面的代码直接照搬IDA反编译的结果
        {
                v8 = arr1[2 * v4];
                if (v8 < 48 || v8 > 57)
                        v9 = v8 - 87;
                else
                        v9 = v8 - 48;
                v10 = arr2[2 * v4];
                v11 = 16 * v9;
                if (v10 < 48 || v10 > 57)
                        v12 = v10 - 87;
                else
                        v12 = v10 - 48;
                for (v5 = 32; v5 < 127; v5++)//代入一个个去试等式成立的条件
                {
                        v6 = (v5 >> 4) % 16;
                        v7 = (16 * v5 >> 4) % 16;
                        if ((unsigned __int8)arr3[16 * v6 + v7] == ((v11 + v12) ^ 0x19))//找到正确的字符就加入flag
                        {
                                flag[v4] = v5;
                                break;
                        }
                }

                v4++;
                if (v4 >= 35)
                {
                        flag[v4] = 0;//flag字符串末尾补\0
                        break;
                }
        }

        printf("%s\n", flag);
        system("pause");
        return 0;
}

4.png

0x5总结

  1.x32dbg手脱UPX那里浪费了时间,就是个随机基址的问题。
  2.这个程序的逻辑并不难,脱壳后放入IDA可以清晰的看到爆破条件,即使看不懂那个判断函数,也可以把代码copy出来爆破。
  3.主要复习了一维数组和二维数组的识别,认识了一下x32dbg的界面和简单使用。
  4.找最后一个二维数组时,没想到什么好办法,也不会脚本,纯体力活给它一个个找出来,从前到后花了6个小时才做出来。
  5.逆向还是要耐心和技巧,逆向逆向就是倒着思考问题,由果寻因的过程。

0x6参考资料

1.[我的代码传记]upx脱壳重定位表修复](https://www.52pojie.cn/thread-1295193-1-1.html)
2.https://www.cnblogs.com/DirWang/p/12236700.html

  PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!

免费评分

参与人数 47吾爱币 +47 热心值 +42 收起 理由
万年老鱼精 + 1 + 1 用心讨论,共获提升!
Forget# + 1 不明觉厉!
三千尺 + 1 + 1 np
fk666 + 1 谢谢@Thanks!
L.7_129 + 1 + 1 谢谢@Thanks!
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
5721 + 1 + 1 我很赞同!
LJJ001 + 1 我很赞同!
nixiang_0607 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
醉得意人心 + 1 + 1 我很赞同!
yelangpck + 1 + 1 我很赞同!
哨兵的牛油果 + 1 + 1 用心讨论,共获提升!
yan182 + 1 + 1 谢谢@Thanks!
火神猎杀者 + 1 + 1 用心讨论,共获提升!
ls990928 + 1 + 1 热心回复!
Zimin + 1 用心讨论,共获提升!
班长的男人 + 1 + 1 谢谢@Thanks!
WAlitudealiy + 1 用心讨论,共获提升!
queenmly + 1 用心讨论,共获提升!
hjthack + 1 + 1 热心回复!
小白想学技术 + 1 + 1 用心讨论,共获提升!
西部飞侠 + 1 + 1 用心讨论,共获提升!
一千二十四 + 1 我很赞同!
zxcv12 + 1 + 1 谢谢@Thanks!
haogl + 1 + 1 用心讨论,共获提升!
wugeshenhuaking + 1 用心讨论,共获提升!
GleeChan + 1 + 1 凡事不白嫖
yujianwo + 1 + 1 谢谢@Thanks!
hjryje + 1 我很赞同!
深水夜藏 + 1 + 1 我很赞同!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
evill + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
风水天空 + 1 + 1 好样的
阿斯顿2 + 1 + 1 用心讨论,共获提升!
alittlebear + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lishang0808 + 1 我很赞同!
xmztz + 1 + 1 谢谢@Thanks!
Pancoes + 1 + 1 我很赞同!
zxc123Qwe789 + 1 + 1 用心讨论,共获提升!
kyxlf2020 + 1 谢谢@Thanks!
look1232000 + 1 + 1 我很赞同!
xiaochengzi + 1 + 1 我很赞同!
SjZj + 1 + 1 谢谢@Thanks!
wxing + 1 + 1 谢谢@Thanks!
Link_Stark + 1 + 1 我很赞同!
杰诺斯 + 1 + 1 我很赞同!
/sakura/ + 1 + 1 谢谢@Thanks!

查看全部评分

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

头像被屏蔽
18073698066 发表于 2020-11-30 08:18
提示: 作者被禁止或删除 内容自动屏蔽
杰诺斯 发表于 2020-11-28 21:46
枫叶飞向海 发表于 2020-11-28 21:52
astarl 发表于 2020-11-28 22:10
开始java的的日常第34天路过,一起加油
我吃小朋友 发表于 2020-11-28 22:19
学历怎么样了
look1232000 发表于 2020-11-28 22:30
有高清视频学基础么?
aibgds 发表于 2020-11-28 23:26

支持一下
5524152 发表于 2020-11-28 23:33
支持支持
safer 发表于 2020-11-28 23:45
支持支持,学习一下。
吾心随风 发表于 2020-11-29 00:10
支持一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-25 13:12

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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