1、前言

公司大拿给写的一个CTF逆向程序,提升我们组内人员的水平。

基于对话框MFC框架开发,使用EDIT控制特性隐藏Flag,可借助spy4win之类窗体工具找出Flag。
程序加UPX壳,已对壳信息混淆处理,PEiD无法识别出壳信息。
DLL 依赖情况如图所示。

2、思路

程序用IDA查看的时候,因为有壳混淆后是没法跟下去的。这道题比较简单,破解还是常规思路。。。

  • 1)手动脱UPX壳
  • 2)IDA查找字符串,获取信息
  • 3)跟踪调用的函数

3、过程

1、脱壳

UPX是一款常用的压缩壳,单步跟踪法或者是ESP定律都能很快的脱掉它。

单步跟踪到如下反汇编指令处:


00406A10 pushad
00406A11 mov esi,ctf02.00406000
00406A16 lea edi,dword ptr ds:[esi-0x5000]
00406A1C push edi
00406A1D or ebp,-0x1
00406A20 jmp short ctf02.00406A32

F8单步向下运行,遇到向上的跳转就F4到下一条指令去,不让自己迷失在各种解密操作指令中。

00406A32 mov ebx,dword ptr ds:[esi]
00406A34 sub esi,-0x4
00406A37 adc ebx,ebx
00406A39 jb short ctf02.00406A28 ; 向上跳转,跳转实现向上运行
00406A3B mov eax,0x1 ; F4运行到此处,遇到红色跳转就下一条
00406A40 add ebx,ebx
00406A42 jnz short ctf02.00406A4B
00406A44 mov ebx,dword ptr ds:[esi]
00406A46 sub esi,-0x4
00406A49 adc ebx,ebx
00406A4B adc eax,eax
00406A4D add ebx,ebx
00406A4F jnb short ctf02.00406A40
00406A51 jnz short ctf02.00406A5C
00406A53 mov ebx,dword ptr ds:[esi]
00406A55 sub esi,-0x4
00406A58 adc ebx,ebx
00406A5A jnb short ctf02.00406A40
00406A5C xor ecx,ecx
00406A5E sub eax,0x3
00406A61 jb short ctf02.00406A70
00406A63 shl eax,0x8
00406A66 mov al,byte ptr ds:[esi]
00406A68 inc esi ; ctf02.0040600B
00406A69 xor eax,-0x1
00406A6C je short ctf02.00406AE2
00406A6E mov ebp,eax
00406A70 add ebx,ebx

接下来会遇见两个向上的跳转,一个小跳转,一个大跳转。

我们在NOP指令的下一行代码F4运行到那一条,接下来的操作就比较重复化,遇到跳转就F4到下一条。

然后遇到popad指令的时候说明我们距离OEP就不远了!

00406ABD mov al,byte ptr ds:[edx]
00406ABF inc edx ;
00406AC0 mov byte ptr ds:[edi],al
00406AC2 inc edi ;
00406AC3 dec ecx
00406AC4 jnz short ctf02.00406ABD ; 小跳转
00406AC6 jmp ctf02.00406A2E ; 大跳转
00406ACB nop
00406ACC mov eax,dword ptr ds:[edx] ; F4运行到此处
00406ACE add edx,0x4
00406AD1 mov dword ptr ds:[edi],eax
00406AD3 add edi,0x4
00406AD6 sub ecx,0x4
00406AD9 ja short ctf02.00406ACC ; 又是一个跳转的地方
00406ADB add edi,ecx ; F4运行到此处
00406ADD jmp ctf02.00406A2E ; 大跳转,F4运行到下一条语句
00406AE2 pop esi ;
00406AE3 mov edi,esi ; F4运行到此处
00406AE5 mov ecx,0x3B
00406AEA mov al,byte ptr ds:[edi]
00406AEC inc edi ;
00406AED sub al,0xE8
00406AEF cmp al,0x1
00406AF1 ja short ctf02.00406AEA ; 小跳转
00406AF3 cmp byte ptr ds:[edi],0x1 ; F4运行到此处
00406AF6 jnz short ctf02.00406AEA
00406AF8 mov eax,dword ptr ds:[edi] ; F4运行到此处
00406AFA mov bl,byte ptr ds:[edi+0x4]
00406AFD shr ax,0x8
00406B01 rol eax,0x10
00406B04 xchg ah,al
00406B06 sub eax,edi ;
00406B08 sub bl,0xE8
00406B0B add eax,esi ;
00406B0D mov dword ptr ds:[edi],eax
00406B0F add edi,0x5
00406B12 mov al,bl
00406B14 loopd short ctf02.00406AEF ; 循环操作
00406B16 lea edi,dword ptr ds:[esi+0x4000] ; F4运行到此处
00406B1C mov eax,dword ptr ds:[edi]
00406B1E or eax,eax
00406B20 je short ctf02.00406B67
00406B22 mov ebx,dword ptr ds:[edi+0x4]
00406B25>lea eax,dword ptr ds:[eax+esi+0x68BC]
00406B2C add ebx,esi ;
00406B2E push eax
00406B2F add edi,0x8
00406B32 call dword ptr ds:[esi+0x6920] ;
00406B38 xchg eax,ebp ;
00406B39 mov al,byte ptr ds:[edi]
00406B3B inc edi ;
00406B3C or al,al
00406B3E je short ctf02.00406B1C
00406B40 mov ecx,edi ;
00406B42 jns short ctf02.00406B4B
00406B44 movzx eax,word ptr ds:[edi]
00406B47 inc edi ;
00406B48 push eax
00406B49 inc edi ;
00406B4A db B9
00406B4B push edi ;
00406B4C dec eax
00406B4D repne scas byte ptr es:[edi]
00406B4F push ebp ;
00406B50 call dword ptr ds:[esi+0x6924] ;
00406B56 or eax,eax
00406B58 je short ctf02.00406B61
00406B5A mov dword ptr ds:[ebx],eax
00406B5C add ebx,0x4
00406B5F jmp short ctf02.00406B39 ; 无条件跳转
00406B61 call dword ptr ds:[esi+0x6934] ;
00406B67 mov ebp,dword ptr ds:[esi+0x6928] ; F4运行到此处
00406B6D lea edi,dword ptr ds:[esi-0x1000]
00406B73 mov ebx,0x1000
00406B78 push eax
00406B79 push esp
00406B7A push 0x4
00406B7C push ebx
00406B7D push edi ;
00406B7E call ebp ;
00406B80 lea eax,dword ptr ds:[edi+0x207]
00406B86 and byte ptr ds:[eax],0x7F
00406B89 and byte ptr ds:[eax+0x28],0x7F
00406B8D pop eax
00406B8E push eax
00406B8F push esp
00406B90 push eax
00406B91 push ebx
00406B92 push edi ;
00406B93 call ebp ;
00406B95 pop eax
00406B96 popad ; 到这里的时候说明快到OEP了
00406B97 lea eax,dword ptr ss:[esp-0x80]
00406B9B push 0x0
00406B9D cmp esp,eax
00406B9F jnz short ctf02.00406B9B
00406BA1 sub esp,-0x80
00406BA4 jmp ctf02.00401750 ; 跳转到OEP

到了00406BA4 这里的时候,我用OD插件-Ollydump脱壳。

2、IDA查看

脱了壳后的程序,用IDA看就没有障碍了。

IDA打开后-View - Open Subviews - Srings

然后X键,查看哪个函数在引用它,F5查看C源码就确认出Flag了。

signed int __thiscall sub_4012B0(CDialog *this)
{
CDialog *v1; // esi@1
HMENU v2; // eax@1
struct CMenu *v3; // edi@1
LPCSTR lpNewItem; // [sp+8h] [bp-10h]@2
int v6; // [sp+14h] [bp-4h]@2 v1 = this;
CDialog::OnInitDialog(this);
v2 = GetSystemMenu(*((HWND *)v1 + 8), 0);
v3 = CMenu::FromHandle(v2);
if ( v3 )
{
CString::CString(&lpNewItem);
v6 = 0;
CString::LoadStringA((CString *)&lpNewItem, 0x65u);
if ( *((_DWORD *)lpNewItem - 2) )
{
AppendMenuA(*((HMENU *)v3 + 1), 0x800u, 0, 0);
AppendMenuA(*((HMENU *)v3 + 1), 0, 0x10u, lpNewItem);
}
v6 = -1;
CString::~CString((CString *)&lpNewItem);
}
SendMessageA(*((HWND *)v1 + 8), 0x80u, 1u, *((_DWORD *)v1 + 40));
SendMessageA(*((HWND *)v1 + 8), 0x80u, 0, *((_DWORD *)v1 + 40)); //发送消息到窗口
CWnd::SetWindowTextA((CDialog *)((char *)v1 + 96), "6C9F69EF-C170-4e43-A007-9AA3526823DB"); //设置文本
SendMessageA(*((HWND *)v1 + 32), 0xCCu, 0x2Eu, 0);
return 1;
}

4、附件下载地址

https://github.com/zprogram/zprogram.github.io/blob/master/Blog_attachment/CTF/CTF_REVERSE_ctf02_查找字符串.zip

5、参考

手脱UPX壳的几种方法

http://blog.csdn.net/xiaoyuai1234/article/details/51463501

【CTF REVERSE】ctf02-查找字符串的更多相关文章

  1. 在文件夹中 的指定类型文件中 查找字符串(CodeBlocks+GCC编译,控制台程序,仅能在Windows上运行)

    说明: 程序使用 io.h 中的 _findfirst 和 _findnext 函数遍历文件夹,故而程序只能在 Windows 下使用. 程序遍历当前文件夹,对其中的文件夹执行递归遍历.同时检查遍历到 ...

  2. php查找字符串首次出现的位置 判断字符串是否在另一个字符串中

    strpos - 查找字符串首次出现的位置 说明 int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] ) 返回 nee ...

  3. 查找字符串的 KMP 算法

    查找字符串是我们平常编程过程中经常遇到的,现在介绍一种查找字符串算法,增加程序的执行速度. 通常我们是这么写的: /* content: search a string in a othor stri ...

  4. 回朔法/KMP算法-查找字符串

    回朔法:在字符串查找的时候最容易想到的是暴力查找,也就是回朔法.其思路是将要寻找的串的每个字符取出,然后按顺序在源串中查找,如果找到则返回true,否则源串索引向后移动一位,再重复查找,直到找到返回t ...

  5. Lua查找字符串注意

    问题: 使用Lua写Wireshark插件时,经常匹配字符串.今天使用string.find()函数查找字符串”max-age”,没有找到. 分析: local index = string.find ...

  6. Javascript 查找字符串中出现最多的字符和出现的次数

    <script type="text/javascript"> //查找字符串中出现最多的字符和出现的次数 var str = 'Thatwheneying its o ...

  7. 查找字符串(C++实现)

    查找字符串(C++实现),不使用库函数: // SubString.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include < ...

  8. php查找字符串是否存在

    strstr //搜索字符串在另一字符串中的首次出现(对大小写敏感) //该函数返回字符串的其余部分(从匹配点).如未找到则返回 false stristr //查找字符串在另一字符串中第一次出现的位 ...

  9. linux上查找文件存放地点和文件中查找字符串方法

    一.查找文件存放地点 1.locate 语法:locate <filename> locate命令实际是"find -name"的另一种写法,但是查找方式跟find不同 ...

随机推荐

  1. day22 collection 模块 (顺便对比queue也学习了一下队列)

    collection 定义命名元祖,让元祖的每个元素可以通过类似对象属性的方法用".属性"及其方便的取值. 定义可前后拿取值且可迭代的双端队列 定义有顺序的字典 定义有默认值的字典 ...

  2. Python的二叉树实现

    二叉树需要实现的功能及思路 找到最小值 没什么好说的就是二叉树最左下的顶点 找到最大值 没什么好说的就是二叉树最右下的顶点 插入 分情况,如果二叉树为空那么直接直接设置成根节点就好了.否则就逐层向下, ...

  3. Web Performance and Load Test Project错误集

    当我们创建Web Performance and Load Test Project时,经常会遇到下面这些问题: 1. 当点击Add Recording时, 左边的record tree没有出现: 解 ...

  4. 【转】stm32CubeMx上移植自己的printf()和scanf()函数

    要想printf()和scanf() 函数工作,我们需要把printf()和scanf() 重新定向到串口中.重定向是指用户可以自己重写C 的库函数,当连接器检查到用户编写了与C 库函数相同名字的函数 ...

  5. UVALive - 6436(DFS)

    题目链接:https://vjudge.net/contest/241341#problem/C 题目大意:给你从1到n总共n个数字,同时给你n-1个连接,同时保证任意两个点之间都可以连接.现在假设任 ...

  6. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

  7. activeMQ点对点

    摘要: ActiveMQ 点对点消息 Point-to-Point 是一对一 创建消息生产者 /**  * 点对点消息生产者  *   * @author Edward  *   */ public  ...

  8. Java设计模式--缺省适配器模式

    我认为这个模式比较常见,还记得我们学习Swing的时候吗,有没有见过很多Adapter?那时候不知道Adapter的意义所在,但至少知道他能够省去我们不需要的实现. 这个社会有N中职业(job),但是 ...

  9. SQL Server 操作XML数据

    .xml.exist 输入为XQuery表达式,返回0,1或是Null.0表示不存在,1表示存在,Null表示输入为空 .xml.value 输入为XQuery表达式,返回一个SQL Server标量 ...

  10. java代码示例(7-1)

    Dog类 /*** * 宠物狗狗类,使用权限修饰符private和public进行封装 * @author chenyanlong * 日期:2017/10/15 */ package com.hp. ...