首页
社区
课程
招聘
[原创][第一阶段◇第三题]看雪论坛.腾讯公司2008软件安全技术竞赛
发表于: 2008-10-8 18:39 2672

[原创][第一阶段◇第三题]看雪论坛.腾讯公司2008软件安全技术竞赛

2008-10-8 18:39
2672
1,用od打开,然后用godup插件在入 map文件,感谢大大提供这个东东,省了不少事哈
2,然后ctrl + n 找到 OnBnClickedBtnCrash 这个函数 地址00420D20,下断点,F9  运行到这,然后单步,运行到
00420D81  |.  E8 7CE0FEFF   call    <__snwprintf                0040ee02 f>; \_snwprintf
开始出错, 不管那么多,自己先把OnBnClickedBtnCrash 函数简单 逆下

#include <stdio.h>
#include <windows.h>

double g_pi = 1.314159;
void *g_this = (void *)0x12FE84;
DWORD g_dw=0x4D2268EC;
WORD g_w=0;

#pragma pack(push,2)

struct stTest
{
        void *lpThis;
        WORD w;
        WCHAR wszDest[0x3F];
        void *lpUnkown;
        DWORD dw;
        double f;
};
#pragma pack(pop) // packing is 8

void __cdecl calc2PI()
{
        stTest stMyTest;
        stMyTest.dw=g_dw;
        stMyTest.lpThis=g_this;
        stMyTest.w=g_w;
        memset(stMyTest.wszDest,0,0x7E);
        stMyTest.f=g_pi+g_pi;
        _snwprintf((WCHAR*)(&stMyTest.w),0x40,L"PI * 2 = %f",stMyTest.f);   
        wprintf( L"%s\n", stMyTest.wszDest);
}

int main(int argc, char* argv[])
{       
        calc2PI();
        return 0;
}

然后用od加载这个程序,对照着看下,发现_snwprintf 完全不一样,晕倒,为什么这样了,难道是加了什么壳,没脱好吗,有可能, 这里 想到 解决的方法 新导入一个 输入函数_snwprintf ,然后 把 原来的_snwprintf函数,直接跳到 我 新导入的函数里, 先试下吧,呵呵
3. 开始添加一个输入函数_snwprintf ,第二题死了不少脑细胞,我就不手动加了,直接拿出 LordPE 加一个_snwprint f, dll 为 msvcrt.dll ,然后把:
0040EE02 >    55            push    ebp                        ;_snwprintf

改成
0040EE02 > $- FF25 18B04300 jmp     dword ptr [<&msvcrt._snwprintf>]       ;  msvcrt._snwprintf
然后直接保存,运行,ok,正常了,果然如此,脱壳没脱干净哈

4.完

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 407
活跃值: (125)
能力值: ( LV13,RANK:280 )
在线值:
发帖
回帖
粉丝
2
上午提交答案,心里总不踏实,有跟了一个晚上,感觉上午提交有点草率了,在提交一份,心里有个底哈 
1,从 00420D81  |.  E8 7CE0FEFF   call    <__snwprintf                0040ee02 f>; \_snwprintf  
出错的地方F7跟进去,来到
0040EE7E  |> \57            push    edi
0040EE7F  |.  8D45 14       lea     eax, dword ptr [ebp+14]
0040EE82  |.  50            push    eax
0040EE83  |.  53            push    ebx
0040EE84  |.  FF75 10       push    dword ptr [ebp+10]
0040EE87  |.  8D45 E0       lea     eax, dword ptr [ebp-20]
0040EE8A  |.  50            push    eax
0040EE8B  |.  E8 E1490000   call    <__woutput_l                00413871 f  >   //到这里
继续跟进到
00413DEC  |.  50            |push    eax
00413DED  |.  FF75 94       |push    dword ptr [ebp-6C]
00413DF0  |.  0FBEC2        |movsx   eax, dl
00413DF3  |.  FF75 E8       |push    dword ptr [ebp-18]
00413DF6  |.  895D D8       |mov     dword ptr [ebp-28], ebx
00413DF9  |.  50            |push    eax
00413DFA  |.  FF75 E0       |push    dword ptr [ebp-20]
00413DFD  |.  8D45 88       |lea     eax, dword ptr [ebp-78]
00413E00  |.  56            |push    esi
00413E01  |.  50            |push    eax
00413E02  |.  FF35 C8A04200 |push    dword ptr [42A0C8]                      ;  <TestFloa.__fptrap                   0041ae1f f   libcmt:crt0fp.obj>
00413E08  |.  E8 3FEFFFFF   |call    <__decode_pointer           00412d4c f >
00413E0D  |.  59            |pop     ecx
00413E0E  |.  FFD0          |call    eax                          //在里出错
查了下__decode_pointer 函数,作用是对[42A0C8]  里的地址 进行解密,然后返回给 eax,最后call 到这个解密的地址,所以,判断,出错应该是 这个解密的地址的问题,然后 对42A0C8,下一个 硬件写入断点,重新运行程序,来到:
00415CEC >/$  56            push    esi
00415CED  |.  57            push    edi
00415CEE  |.  33FF          xor     edi, edi
00415CF0  |>  8DB7 B0A04200 /lea     esi, dword ptr [edi+42A0B0]
00415CF6  |.  FF36          |push    dword ptr [esi]
00415CF8  |.  E8 D8CFFFFF   |call    <__encode_pointer           00412cd5 f >
00415CFD  |.  83C7 04       |add     edi, 4
00415D00  |.  83FF 28       |cmp     edi, 28
00415D03  |.  59            |pop     ecx
00415D04  |.  8906          |mov     dword ptr [esi], eax           //在这里断下
00415D06  |.^ 72 E8         \jb      short 00415CF0
00415D08  |.  5F            pop     edi
00415D09  |.  5E            pop     esi
00415D0A  \.  C3            retn
在00415D04  断下,这里说下这个call的作用,循环得到  [edi+42A0B0]  地址,然后用__encode_pointer 进行加密,这里__encode_pointer 和 __decode_pointer 是对应的
一个加,一个解,显然这个 地址是有问题的, 于是,返回上一层来到0040F640:
0040F618 >/$  833D 5C404200>cmp     dword ptr [42405C], 0                          0040F61F  |.  74 1A         je      short 0040F63B        // 这里判断__fpmath 是否等于零
0040F621  |.  68 5C404200   push    0042405C
0040F626  |.  E8 65670000   call    <__IsNonwritableInCurrentImage 00415d90 >
0040F62B  |.  85C0          test    eax, eax
0040F62D  |.  59            pop     ecx
0040F62E  |.  74 0B         je      short 0040F63B             //这里通过__IsNonwritableInCurrentImage 函数检查0042405C所在的区段 是否为只读
0040F630  |.  FF7424 04     push    dword ptr [esp+4]
0040F634  |.  FF15 5C404200 call    dword ptr [42405C]                       ;  <TestFloa.__fpmath                   00411e26 f   libcmt:fpinit.obj>      //只读执行
0040F63A  |.  59            pop     ecx
0040F63B  |>  E8 AC660000   call    <__initp_misc_cfltcvt_tab   00415cec f  >
0040F640  |.  68 98244200   push    00422498                                  //返回到这
0040F645  |.  68 7C244200   push    0042247C
0040F64A  |.  E8 36FFFFFF   call    <__initterm_e               0040f585 f  >
0040F64F  |.  85C0          test    eax, eax

为了说明问题,把call前面的代码都贴上,这个是 _cinit 函数的代码,为了看着舒服,找到他的原代码:
int __cdecl _cinit (
        int initFloatingPrecision
        )
{
        int initret;

        /*
         * initialize floating point package, if present
         */
#ifdef CRTDLL
        _fpmath(initFloatingPrecision);
#else  /* CRTDLL */
        if (_FPinit != NULL &&
            _IsNonwritableInCurrentImage((PBYTE)&_FPinit))
        {
            (*_FPinit)(initFloatingPrecision);
        }
        _initp_misc_cfltcvt_tab();
#endif  /* CRTDLL */
到这里已经很显然了,应该是0042405C所在的区段 只读条件不成立,导致浮点指针包未能初始化,最后导致错误,为了证实,用LordPE 看了下,0042405C所在.rdata 区段为C0000040,可写,导致错误

2,解决方法 
   根据_cinit 代码,让#ifdef CRTDLL 条件满足,这个不熟悉,猜应该是个dll吧,可以在vc工程里 导入CRTDLL,或者用LordPE 修改.rdata 为只读40000040就可以了,这里也可以修改成60000040 能读能执行 即可 ,或者加个什么壳 ,能改变它的区段的都可以,这里我测试了论坛上大大说的upx壳,成功.

3,最后发个我用LordPE 修改的TestFloat.exe
上传的附件:
2008-10-9 02:29
0
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
3
结果提交时间 14 小时 29 分钟
结果提交时间长度 = 869 分钟
结果提交次数 = 2
结果提交为根本原因
得分 = [(2880 - 869)/2880]^1/5 x 1.0 x 100 - (2 -1 ) x 5 = 88.07
2008-10-9 11:47
0
雪    币: 407
活跃值: (125)
能力值: ( LV13,RANK:280 )
在线值:
发帖
回帖
粉丝
4
[QUOTE=kangaroo;519026]结果提交时间 14 小时 29 分钟
结果提交时间长度 = 869 分钟
结果提交次数 = 2
结果提交为根本原因
得分 = [(2880 - 869)/2880]^1/5 x 1.0 x 100 - (2 -1 ) x 5 = 88.07...[/QUOTE]
请问, 我第一次提交算不算根本原因了,能得多少分呢?
2008-10-9 13:51
0
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
5
以最后一次提交的为准
2008-10-14 14:58
0
游客
登录 | 注册 方可回帖
返回
//