攻防世界 REVERSE 新手区/csaw2013reversing2

攻防世界 REVERSE 新手区/csaw2013reversing2

静态调试方法

在这里插入图片描述

看题目描述,说是运行就能拿到flag,下载运行一下,看来不行

在这里插入图片描述

先查一下有没有加壳,这个没有加壳,而且是个32位的程序

在这里插入图片描述

用IDA32位打开,f5查看伪代码

在这里插入图片描述

接下来就是分析代码了

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  CHAR *lpMem; // [esp+8h] [ebp-Ch]
  HANDLE hHeap; // [esp+10h] [ebp-4h]

  hHeap = HeapCreate(0x40000u, 0, 0);
  lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
  memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
  if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);
  }
  MessageBoxA(0, lpMem + 1, "Flag", 2u);
  HeapFree(hHeap, 0, lpMem);
  HeapDestroy(hHeap);
  ExitProcess(0);
}

先查一下HeapCreate()和HeapAlloc()是干啥的

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

这两条语句是申请了一个大小为Maxcount = 24h的空间

在这里插入图片描述

然后通过字符串拷贝函数memcpy_()将 &unk_409B10中的内容拷贝到lpMem

在这里插入图片描述
在这里插入图片描述

接下来是这个if语句

if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);
  }

sub_40102A() 函数返回的直接就是0,所以不用管

在这里插入图片描述

IsDebuggerPresent() 是一个检测程序是否被调试的函数,如果检测到被调试,则会直接退出,我还试了下

在这里插入图片描述

这反调试反了个寂寞

在这里插入图片描述
在这里插入图片描述

那就先跳过这个直接看后面的语句

MessageBoxA(0, lpMem + 1, "Flag", 2u);

在这里插入图片描述
在这里插入图片描述

这是个输出语句,结合之前弹出的窗口,推出flag就在plMem里面

写了个脚本来输出内容

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int lpMem[37] = {0x0BB,0x0CC,0x0A0,0x0BC,0x0DC,0x0D1,0x0BE,0x0B8,0x0CD,0x0CF,
     0x0BE,0x0AE,0x0D2,0x0C4,0x0AB,0x82,0x0D2,0x0D9,0x93,0x0B3,0x0D4,0xDE,
     0x93,0x0A9,0x0D3,0x0CB,0x0B8,0x82,0x0D3,0x0CB,0x0BE,0x0B9,0x9A,0x0D7,
     0x0CC,0x0DD};
    for(int i = 0 ; i < 36; i++)
    {
       printf("%c",lpMem[i]);
    }
    return 0;

}

运行出来是乱码(废话)

在这里插入图片描述

那唯一还没看的地方就是之前的那个if语句中的内容了

里面有个sub_401000函数用了lpMem作为参数,跟进去查看

if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);
  }

在这里插入图片描述

v2=dword_409B38

在这里插入图片描述

然后看这个循环,前面result的值可以不用管,反正也不会超过这个字符串的长度36

然后天真的我以为这个是隔四个异或一次v2,结果输出的还是乱码

然后我发现了将这个转换下类型会变成四个数。。

在这里插入图片描述
在这里插入图片描述

那个循环应该是依次异或v2中的数,,,根据这个可以写出脚本

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int lpMem[37] = {0x0BB,0x0CC,0x0A0,0x0BC,0x0DC,0x0D1,0x0BE,0x0B8,0x0CD,0x0CF,
     0x0BE,0x0AE,0x0D2,0x0C4,0x0AB,0x82,0x0D2,0x0D9,0x93,0x0B3,0x0D4,0xDE,
     0x93,0x0A9,0x0D3,0x0CB,0x0B8,0x82,0x0D3,0x0CB,0x0BE,0x0B9,0x9A,0x0D7,
     0x0CC,0x0DD};
     int v2[4] = {0xBB,0XAA,0XCC,0XDD};
    for(int i = 0 ; i < 36; i++)
    {
       printf("%c",lpMem[i] ^ v2[ i  % 4]);
    }
    return 0;

}

运行得到结果

在这里插入图片描述

动态调试方法

.用OLLYDDEBUG打开

在这里插入图片描述

按F8一直运行,直到看到这个函数,之前查到了这是个反调试的函数,对照这就是if语句中的判断过程
在这里插入图片描述

if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);
  }

看到调用这个语句的上面还有一个jnz语句,而且跳转还未实现,那这个应该就是if语句中的 || ,因为前面返回的是0,所以要继续判断||右边的值

在这里插入图片描述

在这里插入图片描述

往下看,这里有一个大的跳转,这个大跳转跳完后就直接停止程序,所以双击两下把这个指令改成jnz

在这里插入图片描述

这里还有一个int3指令,int3会引发一个中断,所以要把这个改成nop(意思是什么都不做)

在这里插入图片描述
在这里插入图片描述

改完后的指令

在这里插入图片描述

继续按F8执行,又看到一个jmp指令,直接跳转到结束程序,这个对应的就是 debugbreak(),所以继续把它改成nop

在这里插入图片描述

   __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);

继续往下看,又是一个jmp指令,这里对应的是 ExitProcess(0xFFFFFFFF),同样的把它改成nop

在这里插入图片描述

   __debugbreak();
    sub_401000(v3 + 4, (int)lpMem);
    ExitProcess(0xFFFFFFFF);

改完后的指令,这里改完后会自动变成两个nop,我也不知道为啥

在这里插入图片描述

然后按F8继续运行就行,运行到这里的时候会弹出来一个空白的框,随便点一个按钮然后继续运行就行

在这里插入图片描述

在这里插入图片描述

继续运行,flag已经出来了

在这里插入图片描述
在这里插入图片描述

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ofo300

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值