River5tone

逆向题目WriteUPs

字数统计: 4.8k阅读时长: 21 min
2018/11/06 Share

持续更新——


第一次IDC脚本:20180911practise1test2

flag:nctf{Embr4ce_Vm_j0in_R3}

  1. 64位elf文件。

  2. IDA汇编&伪代码静态分析+虚拟机远程调试分析:

    输入一串字符,该字符串长度应为18h,经过call sub_4005B6的运算,将字符串进行处理,然后遍历字符串每位与dword_601060的对应位匹配。

    那么关键就是对字符串进行的运算处理部分了,感受一波伪代码,挺清晰的:

    大体意思就是有炒鸡多的操作数,每3个字节为一个单位,第一个做switch判断做哪种运算,第二个为改变字符在字符串中的数组下标,第三个为用于运算的数。

  3. 15000那么多的数据,5000个操作,要用脚本了叭,还没写过嘤嘤嘤

    嗯嗯终于学了一下,一开始完全摸不着头脑,后来看了看逆向第6题,又看了看网上的小例子,啊原来就是和C很像,有一些特殊的函数和用法:

    1. i+=3要写为i=i+3
    2. PatchByte(address,data),将data覆盖address;
    3. Byte(address),取出地址中1个字节的数据;
    4. Message()的用法与printf()差不多;
    5. switch不能用。

    一开始出现各种问题,各种字母打错之类的嘤嘤嘤,后来运行了发现是一堆乱码emmm,原来是直接写了那个函数里的运算忘了变成逆运算了emmm。

    脚本大致思路:将匹配字符串dword_601060(注意是dword!)做逆运算,5000个操作倒着进行,+--+*/异或的逆运算还是它本身

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //#include <idc.idc>
    auto from1 = 0x6010C0;
    auto from2 = 0x601060;

    auto i,a,b,c;

    for(i = 14999; i > 0; i = i-3){
    truea = Byte(from1 + i - 2);
    trueb = Byte(from1 + i - 1);
    truec = Byte(from1 + i);
    trueif (a==1) PatchByte(from2 + b*4, Byte(from2+b*4) - c);
    trueelse if (a==2) PatchByte(from2 + b*4, Byte(from2+b*4) + c);
    trueelse if (a==3) PatchByte(from2 + b*4, Byte(from2+b*4) ^ c);
    trueelse if (a==4) PatchByte(from2 + b*4, Byte(from2+b*4) / c);
    trueelse if (a==5) PatchByte(from2 + b*4, Byte(from2+b*4) ^ Byte(from2+c*4));
    trueelse continue;
    }

    for(i = 0; i < 24; i++){
    trueMessage("%c",Byte(from2+i*4));
    }
  4. Output window得到flag nctf{Embr4ce_Vm_j0in_R3}

一个简单但卡我的垃圾题:20180918practise2test1

flag:flag{123_Buff3r_0v3rf|0w}

  1. exe。

  2. F5查看伪代码,弹对话框,输入字符,flag形式为flag{输入串_Buff3r_0v3rf|0w}

  3. 动态分析对于输入字符串的限制:

    • 输入字符串不超过6位;

    • 输入字符串4~6位为xyz

    • atoi函数返回值+1为123;

      之前写C的时候用过atoiitoa函数,数字字符串与整形之间的转换,比如本题目中的“122”就会变为数值122。然而,然而……一开始还是绕了好久,记忆不清同时没有立即再去百度这个函数驱使我去仔细分析atoi函数并陷入了迷茫……甚至还写了C来实现这个函数……哭死哭晕……

  4. 所以输入1233xyz,得到弹出的新对话框:

    得到flag。嘤嘤嘤,怎么觉得第一题比第二题还难怎么能绕这么一大圈嘤嘤嘤。

写程序处理一大串(稍)复杂指令:20180918practise2test2

flag:nctf{th3_vM_w1th0ut_dAta}

  1. 64位elf文件。

  2. 静态分析一遍过程:

    输入flag,长度应为19h,即25。然后经过一个奇怪的模块Sorry, this node is too big to display,(这尼玛什么鬼),空格看了一下,非常长的操作:对694100开始的一小段赋初值,之后分为很多段,每段开始都是对输入串的某些位进行运算,然后是对从6941786941E0逐字与前一位进行异或,这一部分为无用操作。然后也是字符串中每一位一个个与预设匹配串dword_694060进行匹配,所有位匹配成功,则Correct

  3. 很长的没办法F5的那一段不知如何下手,百度了一下IDA too big function,通过修改配置文件IDA 7.0\cfg\hexrays.cfg中的MAX_FUNCSIZE ,64改为1024,即可解决。然后等了好久终于F5出来。

  4. 程序分析明白清楚,束手无策.jpg,这个和上一次的题目不一样的地方是操作不是存在数据里的,而是写成指令的,怎么对指令写逆操作脚本还是很懵逼。后来从网上得到将指令搞下来写解密程序的思路。

    Ctrl+A将伪代码指令复制到txt文档中,掐头去尾留中间部分(没错复制粘贴这里卡了好久嘤嘤嘤,试过各种,还试着用过savefile,然而我太傻了,这样save下来的也是数据啊嘤嘤嘤嘤嘤嘤)。然后写C++程序来处理文本:

    1. 文件操作没怎么用过:

      • FILE *fp; 文件指针;
      • fp = fopen("2.txt","r"); 打开文件,r为只读。
      • fscanf(fp," %c",&c); 文件中的读入。
      • fclose(fp); 关闭文件
    2. 顺序读一遍,并过滤掉无用操作行;有用操作行留下操作位数,运算符,被运算数;

      这个过程有些复杂,各种细节问题都是在调试过程中发现的orz:

      • 先在文本中运用查找将++--,均改为+=-=(好在数量不多);
      • 然后注意异或时的数,有的1位有的两位,有的前面有0x,有的后面有u
      • 最后的;记得读掉。
      • !!!重要!!!:每一步都要记得模256!!!
      • 地址是16进制,异或的被运算数也是16进制,C中可以直接用"%x"来读!!!蠢哭!!!这样就不用怎么去考虑0xu的问题了!
    3. 逆序处理模式匹配串(注意是双字节型!)。最后输出得到flag。

    代码嘤调试改了好久(写的有些麻烦了,十六进制可以更简单地处理,如果用python应该会更简单):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    #include <cstdio>
    #include <cctype>
    #include <cstring>

    const int maxn=5e5;

    unsigned char enc_flag[]={
    0xC0,0x85,0xF9,0x6C,
    0xE2,0x14,0xBB,0xE4,
    0x0D,0x59,0x1C,0x23,
    0x88,0x6E,0x9B,0xCA,
    0xBA,0x5C,0x37,0xFF,
    0x48,0xD8,0x1F,0xAB,
    0xA5
    };

    char op[maxn];
    int num[maxn][2];

    int main()
    {
    FILE *fp;
    int k=0;
    char s[50],c,cc;

    fp=fopen("2.txt","r");
    //顺序处理
    while(~fscanf(fp," %s",s)){
    if(s[0]=='d'){ //无用操作跳过,但是记得要读掉
    fscanf(fp," %s",s);
    fscanf(fp," %s",s);
    continue;
    }
    //十六进制数转换
    num[k][0]=isalpha(s[9])?s[9]-'A'+10:s[9]-'0';
    num[k][0]*=16;
    num[k][0]+=(isalpha(s[10])?s[10]-'A'+10:s[10]-'0');
    fscanf(fp," %c%c",&op[k],&c);
    if(op[k]=='^'){ //如果是异或
    fscanf(fp," %c%c",&c,&cc);
    if(c=='0') //如果有0x
    fscanf(fp," %c%c",&c,&cc);
    num[k][1]=isalpha(c)?c-'A'+10:c-'0';
    if(cc!='u'){ //如果是两位数,u没被读掉
    num[k][1]*=16;
    num[k][1]+=(isalpha(cc)?cc-'A'+10:cc-'0');
    fscanf(fp," %c",&c); //读掉u
    }
    }
    else
    fscanf(fp," %d",&num[k][1]);
    fscanf(fp," %c",&c); //读掉分号
    k++;
    }
    fclose(fp);
    //逆序解密
    for(int i=k-1;i>=0;--i){//printf("%d:%d %c= %d\n",i,num[i][0],op[i],num[i][1]);
    int a=num[i][0],b=num[i][1];
    switch(op[i]){
    case '+':enc_flag[a]-=b;break;
    case '-':enc_flag[a]+=b;break;
    case '^':enc_flag[a]^=b;break;
    }
    enc_flag[a]%=256;
    }
    printf("%s\n",enc_flag);

    return 0;
    }

一个不难适合看汇编代码反编译代码理解错的题目:20180925practise3test1

flag DDCTF-5943293119a845e9bbdbde5a369c1f50@didichuxing.com

IDA静态分析

  • printf的返回值为输出字符的长度;

  • v2的值一开始理解为函数返回值相减右移两位又异或0x41,然而,然而,那并不是函数返回值!

  • v2的值应该是地址相减右移两位再异或0x41

    (char *)start - (char *)sub_100000C90) = 0x100000CB0-0x100000C90 = 0x20

    汇编语句为

    1
    2
    3
    lea     rsi, sub_100000C90		//取的地址!!!
    lea rdi, start
    sub rdi, rsi

    所以v2的值为73

  • byte_100000C90处的字符串用程序实现上诉操作即可解得 DDCTF-5943293119a845e9bbdbde5a369c1f50@didichuxing.com

  • PS:中间觉得v2的值可能不对,就打了表,一开始还进行了不停改变字符串的操作,后来改正确了以后依然难以从128行中找到flag嘤嘤嘤菜哭。

可怕的OD(稍)复杂调试:20180925practise3test2

flag {FLAG:3Ks-grEaT_j0b!}

  1. 32位exe;

  2. IDA打开,一堆函数,各种调用各种,无法阅读;

  3. OD打开,右键字符串搜索(字符串检索法),发现有"你赢了"这样的一条,找到关键函数;

  4. OD打了几个断点动态调试,大体过程是,先对字符串进行异或运算操作,异或的数在动态调试中记下,再与预设串比较;

  5. 异或逆运算解密

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char enc_flag[]={
    0x1B,0x1C,0x17,0x46,0xF4,0xFD,0x20,0x30,
    0xB7,0x0C,0x8E,0x7E,0x78,0xDE
    };

    char x[]={
    true0x28,0x57,0x64,0x6B,0x93,0x8F,0x65,0x51,
    true0xE3,0x53,0xE4,0x4E,0x1A,0xFF
    };

    for(int i=0;i<14;++i){
    trueprintf("%c",enc_flag[i]^x[i]);
    }

.net反编译及其工具初接触:20181002practise4test1

flag:PCTF{Ea5y_Do_Net_Cr4ck3r}

  1. 听CB大佬说Kali有一些逆向的工具,就百度了一下,发现了一个叫做Radare2的工具,可以用 rabin2打印出二进制文件的系统属性、语言、字节序、框架、以及使用了哪些加固技术:

    可以知道这个程序是用Cli语言编写的。然并卵。

  2. 虚拟机中file命令十分好用:

    可知是.net文件。

  3. 用了CB大佬给的工具Gray Wolf

    由上图可知,该程序是将输入的字符串base64一下与预设串进行匹配。

  4. 丢到base64解码网站,得flag。

  5. 感到非常神奇。

python反编译:20181002practise4test2

flag:PCTF{PyC_Cr4ck3r}

  1. 虚拟机中file命令查看文件

    可知程序是由python写的,将test2的后缀改为.pyc即可运行。

  2. CB大佬给了强大的工具Easy Python Decompiler,将.pyc文件反编译为.pyc_dis文件。

  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    # Embedded file name: findkey
    import sys
    lookup = [196, 153, 149, 206, 17, 221, 10, 217, 167, 18,
    truetrue 36, 135, 103, 61, 111, 31, 92, 152, 21, 228,
    truetrue 105, 191, 173, 41, 2, 245, 23, 144, 1, 246,
    truetrue 89, 178, 182, 119, 38, 85, 48, 226, 165, 241,
    truetrue 166, 214, 71, 90, 151, 3, 109, 169, 150, 224,
    truetrue 69, 156, 158, 57, 181, 29, 200, 37, 51, 252,
    truetrue 227, 93, 65, 82, 66, 80, 170, 77, 49, 177,
    truetrue 81, 94, 202, 107, 25, 73, 148, 98, 129, 231,
    truetrue 212, 14, 84, 121, 174, 171, 64, 180, 233, 74,
    truetrue 140, 242, 75, 104, 253, 44, 39, 87, 86, 27,
    truetrue 68, 22, 55, 76, 35, 248, 96, 5, 56, 20,
    truetrue 161, 213, 238, 220, 72, 100, 247, 8, 63, 249,
    truetrue 145, 243, 155, 222, 122, 32, 43, 186, 0, 102,
    truetrue 216, 126, 15, 42, 115, 138, 240, 147, 229, 204,
    truetrue 117, 223, 141, 159, 131, 232, 124, 254, 60, 116,
    truetrue 46, 113, 79, 16, 128, 6, 251, 40, 205, 137,
    truetrue 199, 83, 54, 188, 19, 184, 201, 110, 255, 26,
    truetrue 91, 211, 132, 160, 168, 154, 185, 183, 244, 78,
    truetrue 33, 123, 28, 59, 12, 210, 218, 47, 163, 215,
    truetrue 209, 108, 235, 237, 118, 101, 24, 234, 106, 143,
    truetrue 88, 9, 136, 95, 30, 193, 176, 225, 198, 197,
    truetrue 194, 239, 134, 162, 192, 11, 70, 58, 187, 50,
    truetrue 67, 236, 230, 13, 99, 190, 208, 207, 7, 53,
    truetrue 219, 203, 62, 114, 127, 125, 164, 179, 175, 112,
    truetrue 172, 250, 133, 130, 52, 189, 97, 146, 34, 157,
    truetrue 120, 195, 45, 4, 142, 139]
    pwda = [188, 155, 11, 58, 251, 208, 204, 202, 150, 120,
    true 206, 237, 114, 92, 126, 6, 42]
    pwdb = [53, 222, 230, 35, 67, 248, 226, 216, 17, 209,
    true 32, 2, 181, 200, 171, 60, 108]
    flag = raw_input('Input your Key:').strip()
    if len(flag) != 17:
    print 'Wrong Key!!'
    sys.exit(1)
    flag = flag[::-1]
    for i in range(0, len(flag)):
    if ord(flag[i]) + pwda[i] & 255 != lookup[i + pwdb[i]]:
    print 'Wrong Key!!'
    sys.exit(1)

    print 'Congratulations!!'

    分析代码可知,flag长度为17,逆操作即可得到flag

    1
    2
    for i in range(0, 17):
    trueprint(chr(lookup[i + pwdb[i]] - pwda[i] & 255))

字修改非常复杂很难炒鸡牛啤:20181002practise4test3

flag:{FLAG:A78EC98ADC239E94}

  1. 32位exe文件。

  2. IDA打开之后,汇编如下

    可以得到信息有,密码不长于16位,不为0,call sub_40116B之后,返回值不能为-1

  3. sub_40116B函数内很长很复杂变量很多,要耐心地一点一点分析:

    一个子进程:

    • GetCommandLineW():获取程序的命令行参数,即程序存放的路径。

    • qmemcpy()

      原型:extern void *memcpy(void *dest, void *src, unsigned int count);

      src所指内存区域复制count个字节到dest所指内存区域。srcdest所指内存区域不能重叠,函数返回指向dest的指针。与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。

    • WriteProcessMemory(ProcessInformation.hProcess, (LPVOID)(Context.Eip - 1), &v22, 0xDu, &NumberOfBytesWritten);

      这一句为字修改操作,将v22开始的13个字节写入:90 46 8A 14 0E 30 14 0F 41 3B C8 75 F5

      1
      2
      3
      4
      5
      6
      7
      BOOL WriteProcessMemory(
      HANDLE hProcess, // 想要写的进程句柄
      LPVOID lpBaseAddress,//想要改成代码的地址
      LPVOID lpBuffer, // 要写入的内容的地址
      DWORD nSize, // 准备写入的字节
      LPDWORD lpNumberOfBytesWritten,实际写入的字节
      );
    • 一直卡在cmp [esp+11B8h+DebugEvent.dwDebugEventCode], ebx jnz short loc_11812F1这个循环里,然后学长说关掉杀毒软件emmm……虽然已经把题目路径作为信任区了然而还是不行吗emmm。关掉就正常了嘤嘤嘤卡了好久啊嘤嘤嘤甚至想改寄存器跳过去,然而后面写地址的部分就不对了emmmorz。

    设为断点的地方即WriteProcessMemory修改的地址,关掉火绒安全打开加载的时候为01181145

  4. G查找刚才找到的地址,修改为刚才记录下的90 46 8A 14 0E 30 14 0F 41 3B C8 75 F5

  5. 分析代码可知,算法是将输入字符异或字符串off_98FEC0+1elcome to CFF test!,再将每一位+1,静态分析还有些懵,动态分析之后才确定。

    那么就很容易写出逆操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char enc_flag[]={
    0x25,0x5C,0x5C,0x2B,
    0x2F,0x5D,0x19,0x36,
    0x2C,0x64,0x72,0x76,
    0x80,0x66,0x4E,0x52
    };
    char a[]="elcome to CFF test!";

    for(int i=0;i<16;++i){
    enc_flag[i]-=1;
    enc_flag[i]^=a[i];
    }

    printf("%s\n",enc_flag);

    得到字符串A78EC98ADC239E94

这个题目之前曾分析了好一段时间,然而主要得程序部分,那段很长得截屏部分,前面一段看上去简单的部分没有分析出来在做什么,只知道动态调试的时候遍历了路径和输入字符串,之后后面复杂的部分,就更不理解了;虽然一下能看到v22-v25,但无法知道它们用来做了什么,也知道buffer,v27-v29,应该的值,想过倒推然而无法入手,所以还是要耐心细心的一条条分析,分析一行行的代码目的,可能的关键点。看到不知道什么意思的函数,百度就好。

稍复杂的.net反编译&分析:20181016practise5test1

flag:PCTF{Dot_Net_UnPack3r_yoo}

  1. 也是一个.net文件。

  2. 分别用Gray Wolfdnspy打开看了看,初步分析:

    找到了判别字符串函数:

    这一部分所做的事情是,将我们输入的字符串赋给text,又用那个乱码类中的某个算法对其进行加密并赋给text2,当输入不为空且text2与后面运算得到的字符串匹配的话,即成功。

    乱码名字类做了什么:

    RijndaelAES算法,密钥为某运算后的字符串bytes,模式为ECB,补码方式为PKCS7

    之后又进行了base64

  3. dnspy动态调试:

    点进去关键的操作函数,大致了解是对字符串进行了一系列操作,打断点动态调试,dnspy好强大,非常好用。

    1.

    打断点动态调试,得到AES加密算法的密钥为pctf2016pctf2016pctf2016pctf2016

    2.

    得到匹配字符串为x/nzolo0TTIyrEISd4AP1spCzlhSWJXeNbY81SjPgmk=

  4. 然后我就试图丢到解密网站里去,然而,由于有不可见字符等,就凉了。还是不能偷懒,自己(上网复制粘贴)老老实实写脚本吧(pip包搞了好久python真有意思黑脸.jpg):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import base64
    from Crypto.Cipher import AES

    s = 'x/nzolo0TTIyrEISd4AP1spCzlhSWJXeNbY81SjPgmk='

    key = 'pctf2016pctf2016pctf2016pctf2016'
    aes = AES.new(str.encode(key), AES.MODE_ECB)

    text_decrypted = str(aes.decrypt(base64.decodebytes(bytes(s, encoding='utf8'))).rstrip(b'\0').decode("utf8"))

    print(text_decrypted)

    得到flag如图。

很难MFC相关碰运气看题解也不会做最后瞎几把做:20181016practise5test2

flag:C7C536FC625CEFCD

  1. exe文件,运行后发现确认按钮是灰色的无法点击。

  2. IDA用了下jump by name的功能,查到了一个GetMSG的函数:

    可知输入不超过16位,又发现,输入16位的时候,确定按钮就可以点了。并且不能输入小写字母。

  3. IDA动态调试,F2打断点,随便选择输入0123456789012345,遇到了下面的情况(遇到这种情况都是各种无措,各种瞎几把试):

    手动去了取跳去的地址的地址edx E51458查看:

    发现这里是我的16位输入,之后16位是我的后8位输入,并变成双字节型。

    查看右边列出的调用这些的函数,发现能看的能反编译的sub_CE1970,很长,就去查找了调用这个函数的地方是sub_CE1B80函数(名称右键X):

    小注:

    1
    2
    3
    4
    5
    #define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
    #define HIBYTE(x) (*((_BYTE*)&(x)+1))
    #define BYTEn(x, n) (*((_BYTE*)&(x)+n))
    #define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0)
    #define BYTE2(x) BYTEn(x, 2)

    可计算出经过上面复杂函数的E51458的数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    x0+x1+x2+x3=71
    x0=x1+68
    x1=x2+2
    x2=x3-59

    x5+x6+x7=3
    x6=x4+10
    x6=x7+9
    x4=x5+52

    w31ld0ne,即7733316C64306E65

    仔细分析前面的sub_CE1970函数:

    很复杂很长,分析一遍,逆操作大都可以实现,主要是是byte_E4B0D0数组的查表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    int change[]={
    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/*0x26,0x93,0xFD,0xB7*/,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/*0x1A,0x2C,0x83,0x09*/,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
    };

    int re_change[256];

    void cal_re()
    {
    for(int i=0;i<256;++i){
    re_change[change[i]]=i;
    }
    }

    如果原数是00,那么查出来就会变成b[0]=0x63,那么变回去就是逆表中第0x63个数的值为0x00

    就跟密码学AES中的S盒很像,只不过把二维变成一维查表,本质没有任何差别。

    然后就开始写64遍循环的逆操作。一开始一条一条逆操作,变量也定义了一堆,就这样我居然全逆下来了orz,然而,照着逆,写着写着觉得有些不对,有的地方不是单纯的右=左即可,有一些无用的冗余操作,不仅无用,不应该逆也。仔细又分析了一下,发现是居然是每个变量都进行了4次查表操作orz。(相同变量名称高亮真好看)。哭了。

    然后写程序,觉得很清晰明了了,结果怎么都不对emmm。百度了一下,发现,原来运行的时候,byte_E4B0D0变化了一点点!好坑!我好蠢!所以以后记得要在动态调试的时候取数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char s[]="w31ld0ne";
    int e[8]={119,51,49,108,100,48,110,101};
    int cnt=64;

    cal_re();

    while(cnt--){
    for(int i=0;i<8;++i){
    for(int j=0;j<4;++j){
    e[i]=re_change[e[i]];
    }
    }
    }
  4. 得到flag。

CATALOG
  1. 1. 持续更新——
    1. 1.1. 第一次IDC脚本:20180911practise1test2
    2. 1.2. 一个简单但卡我的垃圾题:20180918practise2test1
    3. 1.3. 写程序处理一大串(稍)复杂指令:20180918practise2test2
    4. 1.4. 一个不难适合看汇编代码反编译代码理解错的题目:20180925practise3test1
    5. 1.5. 可怕的OD(稍)复杂调试:20180925practise3test2
    6. 1.6. .net反编译及其工具初接触:20181002practise4test1
    7. 1.7. python反编译:20181002practise4test2
    8. 1.8. 字修改非常复杂很难炒鸡牛啤:20181002practise4test3
    9. 1.9. 稍复杂的.net反编译&分析:20181016practise5test1
    10. 1.10. 很难MFC相关碰运气看题解也不会做最后瞎几把做:20181016practise5test2