首页
社区
课程
招聘
KCTF2020秋季赛 第二题 异常信号
2020-11-21 07:30 4752

KCTF2020秋季赛 第二题 异常信号

2020-11-21 07:30
4752

垃圾代码 + 反调试 + 壳


程序壳段只有几个函数, 每个函数由于加了大量的垃圾代码, 导致直接看代码并不是太直观


用ApiMonitor看下用了哪些API及调用栈, 

用IDA导出函数的asm, 根据调用栈定位到调用API处, 文本搜索相关的变量引用


反调试API

NtSetInformationThread -> ThreadHideFromDebugger
NtQueryInformationProcess -> DebugPort / DebugObjectHandle / DebugFlags 
CheckRemoteDebuggerPresent
IsDebuggerPresent


创建线程

CreateThread
NtCreateThreadEx


解压缩

cabinet.dll
Decompress // win8+


T0_EntryPoint()
{
    CreateThread(T1);
    CreateThread(T2);
    NtSetInformationThread();
    NtCreateThreadEx(T3);
    LOOP_FOREVER();
}

T1_004DF2B0()
{
    while(1)
    {
        Sleep(100);
        GetThreadContext(GetCurrentThread(), &ctx);
        ctx.Dr0(...);
        ctx.Dr1(...);
        ctx.Dr2(...);
        ctx.Dr3(...);
    }    
}

T2_004EAA70(hT1)
{
    while(1)
    {
        SuspendThread(hT1);
        GetThreadContext(hT1, &ctx);
        ctx.Dr0 = GetProcAddress;
        ctx.Dr1 = GetThreadContext;
        ctx.Dr2 = GetStartupInfoA;
        ctx.Dr3 = GetProcessHeap;
        SetThreadContext(hT1, &ctx);    
        Sleep(100);
    } 
}

// T4_004B6580 => SetWaitableTimer(T4X)
// T4X_004C9960 => 反调试
T3_00464960()
{
    ZwCreateThreadEx(T4); 
    DecompressBlocks();
    
    // CALL [fn]; 
    // fn=stub; 
    // stub: mov eax, imm1
    // stub: xor eax, imm2
    // stub: jmp eax
    PrepareIAT();  
    
    NtHeaders.OptionalHeader.AddressOfEntryPoint = 0x004C9950;
    jmp [Base + NtHeaders.FileHeader.TimeDateStamp] // RealOEP
}


主程序

T1_004010E0(); // CheckCrcOfMain
T2_004016F0(); // CheckForDebugger

// 这里反调试相关的代码有个 32位 -> 64位 -> 32位 的过程
fn()
{
    __asm
    {
        ; 32bit code
        ; ...
    
        ; 32 -> 64
        push    33h
        call    $+5
        add     dword ptr [esp], 5
        retf

        ; 64bit code
        ; ...
        
        ; 64 -> 32
        call    $+5
        mov     dword ptr [rsp+4], 23h
        add     dword ptr [rsp], 0Dh
        retf
        
        ; 32bit code
        ; ...
    
    }
}

// 有限正整数集合中任何两个数的差均不相同,求该集合最大元素的最小值
// hxxps://bbs.csdn.net/topics/10424232
// [0, 2, 6, 24, 29, 40, 43, 55, 68, 75, 76, 85] 
Main_004012B0()
{
    // ...
    
    __asm
    {
        ; 如果是脱过壳的, 需要注意下这里
        mov     ecx, g_ImageBase
        mov     eax, [ecx+_IMAGE_DOS_HEADER.e_lfanew]
        mov     eax, [eax+ecx+28h] ; OptionalHeader.AddressOfEntryPoint
        mov     eax, [eax]
    }
    
    // ..
}


整数集合前面链接里面有, 再转换一下即可得到flag

def print_sn(choices):
    rnds = [
        [
            0x5E67, 0x12E1, 0x475B, 0x7BD4, 0x304E, 0x64C8, 0x1942, 0x4DBC, 0x0236, 0x36B0,
            0x6B29, 0x1FA3, 0x541D, 0x0897, 0x3D11, 0x718B, 0x2604, 0x5A7E, 0x0EF8, 0x4372,
            0x77EC, 0x2C66, 0x60E0, 0x1559, 0x49D3, 0x7E4D, 0x32C7, 0x6741, 0x1BBB, 0x5034,
            0x04AE, 0x3928, 0x6DA2, 0x221C, 0x5696, 0x0B10, 0x3F89, 0x7403, 0x287D, 0x5CF7,
            0x1171, 0x45EB, 0x7A64, 0x2EDE, 0x6358, 0x17D2, 0x4C4C, 0x00C6, 0x3540, 0x69B9,
            0x1E33, 0x52AD, 0x0727, 0x3BA1, 0x701B, 0x2494, 0x590E, 0x0D88, 0x4202, 0x767C,
            0x2AF6, 0x5F70, 0x13E9, 0x4863, 0x7CDD, 0x3157, 0x65D1, 0x1A4B, 0x4EC4, 0x033E,
            0x37B8, 0x6C32, 0x20AC, 0x5526, 0x09A0, 0x3E19, 0x7293, 0x270D, 0x5B87, 0x1001,
            0x447B, 0x78F4, 0x2D6E, 0x61E8, 0x1662, 0x4ADC, 0x7F56, 0x33D0, 0x6849, 0x1CC3,
        ],
        [
            0x5E67, 0x027A, 0x4E00, 0x1986, 0x650D, 0x3093, 0x7C19, 0x479F, 0x1325, 0x5EAB,
            0x2A31, 0x75B8, 0x413E, 0x0CC4, 0x584A, 0x23D0, 0x6F56, 0x3ADD, 0x0663, 0x51E9,
            0x1D6F, 0x68F5, 0x347B, 0x0001, 0x4B88, 0x170E, 0x6294, 0x2E1A, 0x79A0, 0x4526,
            0x10AD, 0x5C33, 0x27B9, 0x733F, 0x3EC5, 0x0A4B, 0x55D1, 0x2158, 0x6CDE, 0x3864,
            0x03EA, 0x4F70, 0x1AF6, 0x667D, 0x3203, 0x7D89, 0x490F, 0x1495, 0x601B, 0x2BA1,
            0x7728, 0x42AE, 0x0E34, 0x59BA, 0x2540, 0x70C6, 0x3C4D, 0x07D3, 0x5359, 0x1EDF,
            0x6A65, 0x35EB, 0x0171, 0x4CF8, 0x187E, 0x6404, 0x2F8A, 0x7B10, 0x4696, 0x121D,
            0x5DA3, 0x2929, 0x74AF, 0x4035, 0x0BBB, 0x5741, 0x22C8, 0x6E4E, 0x39D4, 0x055A,
            0x50E0, 0x1C66, 0x67ED, 0x3373, 0x7EF9, 0x4A7F, 0x1605, 0x618B, 0x2D11, 0x7898,
        ],
    ]
    s = ''
    mx = choices[-1] + 1
    for i in range(mx):
        if i in choices:
            rnd = rnds[0][i]
        else:
            rnd = rnds[1][i]
        s += '%02X' % (rnd & 0xFF)
        s += '%02X' % ((rnd >> 8) & 0xFF)
    print s
    return


def test():
    print_sn([0, 2, 6, 24, 29, 40, 43, 55, 68, 75, 76, 85])
    return


test()



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2020-11-21 08:01 被风间仁编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (2)
雪    币: 210
活跃值: (354)
能力值: ( LV3,RANK:38 )
在线值:
发帖
回帖
粉丝
capser 2020-11-24 10:47
2
0
膜拜大佬,人狠话不多。 不脱壳就强来
雪    币: 12012
活跃值: (4643)
能力值: ( LV5,RANK:77 )
在线值:
发帖
回帖
粉丝
qux 2020-11-24 14:42
3
0

菜鸟问一下,32 -> 64 -> 32 写代码应该怎么写呢?
我是这么写的,然后运行的结果只是输出第一个输出,然后就退出了。
x64dbg调试显示好像是切换的时候出了问题。

```
#include <stdio.h>
int main()
{
    printf("Hello World!\n");
    __asm
    {
        ; 32bit code
        ; ...
        mov eax, 0xA
        ; 32 -> 64
        push    33h
        call    $ + 5
        add     dword ptr[esp], 5
        retf
    }
    // 32bit code
    printf("Hello World! 2\n");
    __asm
    {
        ; 64 -> 32
        call    $ + 5
        ;  mov     dword ptr[rsp + 4], 23h
        ;  add     dword ptr[rsp], 0Dh
        mov     dword ptr[esp + 4], 23h
        add     dword ptr[esp], 0Dh
        retf
    }
    // 32bit code
    printf("Hello World! 3\n");
    return 0;
}
```


最后于 2020-11-24 14:43 被qux编辑 ,原因: 格式调整
游客
登录 | 注册 方可回帖
返回