欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]HDUSEC内核jpg分析

[原创]HDUSEC内核jpg分析

0x1. 去花
首先载入ida,发现有比较多的花指令。那就先去除花指令吧。
此文件花指令格式大概为如下几种:

__asm

{  

        xor eax,eax   

        jz label1

        __emit e7h

        __emit e8h   // call

        __emit e9h   // jmp

label1:

}

__asm

{

        xor eax,eax

        jz label2

        /* junk code */

        __emit 74h // jz

labe2:

}

去除花指令可以用winhex搜索特征码来改成nop,当然直接用idc插件改更方便。简单写个idc脚本
#include <idc.idc>

static main()

{

    auto i,j,from,size;

    from=0x11400; //起始地址

    size=0x1000;//扫描数据块大小

    for ( i=0; i < size;i++ )

    {

        //查找 E7 E8 E9 替换90

        if ((Byte(from) == 0xE7) &&

            (Byte(from+1) == 0xE8) &&

            (Byte(from+2) == 0xE9))

        {

            Message("test\n");

            for(j=0;j<3;j++)

            {

                PatchByte(from,0x90);

                from++;

            }

            continue;  //回到for

        }

        // 查找 33 c0 74 10 ?? ?? ?? ?? …… 后16个替换成90

        if (Byte(from) == 0x33 && Byte(from+1) == 0xC0 && Byte(from + 2) == 0x74 &&

            Byte(from + 3) == 0x10)

        {

            for (j = 0; j < 16; j++)

            {

                PatchByte(from+4, 0x90);

                from++;

            }

            continue;

        }

        from++;

    }

    Message("\n" + "OK\n");

 }

执行了idc脚本后,再用d和c再调整下代码(最好先设置下Number of opcode bytes 为8)。
此时修改的数据是保存在idb数据库文件里的,文件本身是没有被修改的,所以此时如果想用UDA的F5,那就必须还得用winhex等编辑器手动修改。
0x2. 分析代码
为了方便还是用F5吧,所以用winhex修改好。
可以看到,程序写了三个文件。并且在DPC例程里一直在写一个第一字节为0xAA,大小为0xAB的文件。
程序造成蓝屏的原因是因为在DPC例程里读写文件。因为DPC例程是运行在DISPATCH_LEVEL的IRQL级别,因此不能使用分页内存。读写文件必须是分页内存。
动态分析这个sys可以发现是DPC例程在调用11780call的时候,调用ZwCreateFile就蓝屏了。
动态分析的方法在xp上,可以在双击调试的环境下(xp), bp IopLoadDriver + 0x663,再载入驱动,此时断下,
call    dword ptr [edi+2Ch]  进入这个call就可以到DriverEntry。
0x3. 解题
当逆出?源码后,就很简单了。在没逆出之前呢?
写了其他两个文件都是骗人的,我们着重看11780这个call干的事,F5后,双击V2变量。

定义一个大小为0xA8的数组,再重新F5,就可以看到是数组的形式,此时自己用C写到另外一个文件保存下来即可(fread fwrite等)。

如果不能F5,就只能对着机器码了。目的就是获取下面红框里面的数据。

这里用python简单匹配下,再用winhex也可以得到上面的结果。
# -*- coding:utf-8 -*-

import re

__author__ = 'JoyChou'

if __name__ == '__main__':

    fp = open('2.txt', 'r')

    content = fp.read()

    result = re.findall(r'\w{2}C6', content)  #findall以列表形式返回所有匹配结果

    bmp_fp = open('1.txt', 'wb')

    for i in result:  #i都是整数

        szStr = str(i)  #用str将整数转换为字符串

        print '0x%s' % szStr[0:2]

        bmp_fp.write(szStr[0:2])

    # 最后还要加上一个0x00  加上后为0xA8  以及要手动修改B1为C6

    bmp_fp.close()

    fp.close()

最后,可以发现,0xAA和0xA8就差两个'BM'字节,添加到头部,解base64即可。
得到图片

base64解密:hdu1s
这bmp图片大小就0xAA个字节,这是怎么做到的呢?唔
0x4. 代码
#include "ntddk.h"

typedef unsigned long DWORD;

typedef unsigned short WORD;

KDPC dpc;

LARGE_INTEGER DueTime;

KTIMER Timer;

void DriverUnload(IN PDRIVER_OBJECT pDriverObject)

{

    KdPrint(("Leave JoyChou's Driver\n"));

}

VOID test1()

{

    UNICODE_STRING UnicodeString2={0};  // 三个结构都为0,如果不设置length,length将为0

    NTSTATUS nStatus;

    UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,1024);

    UnicodeString2.MaximumLength = 1024;

    // 将200以16进制转换为字符串,最后为字符串 C8

    nStatus = RtlIntegerToUnicodeString(200,16,&UnicodeString2);

    if ( NT_SUCCESS(nStatus))

    {

        KdPrint(("Conver to string succussfully!\n"));

        KdPrint(("Result:%wZ\n",&UnicodeString2));

    }else

    {

        KdPrint(("Conver to string unsuccessfully!\n"));

    }

    //销毁UnicodeString2

    RtlFreeUnicodeString(&UnicodeString2);

}

int test2(int a1)

{

    int result;

    LARGE_INTEGER LocalTime;

    LARGE_INTEGER CurrentTime;

    TIME_FIELDS TimeFields;

    // 得到当前时间(是一个格林威治时间)

    KeQuerySystemTime(&CurrentTime);

    // 转换为当地时间

    ExSystemTimeToLocalTime(&CurrentTime, &LocalTime);

    // 转换为TIME_FIELDS 可读的时间(人类可以理解的时间)

    RtlTimeToTimeFields(&LocalTime, &TimeFields);

    *(ULONG *)a1 = 74017 * TimeFields.Minute + TimeFields.Second + 4625;

    *(ULONG *)a1 = 18 * TimeFields.Hour + 2340 * *(ULONG *)a1;

    result = a1;

    *(ULONG *)a1 >>= 1;

    return result;

}

int __cdecl sub_11780()

{

    ULONG Value; // [sp+0h] [bp-F4h]@1

    char v2[168]; // [sp+4h] [bp-F0h]@1

    NTSTATUS v3; // [sp+ACh] [bp-48h]@1

    UNICODE_STRING String; // [sp+B0h] [bp-44h]@1

    HANDLE Handle; // [sp+B8h] [bp-3Ch]@1

    struct _IO_STATUS_BLOCK IoStatusBlock; // [sp+BCh] [bp-38h]@1

    LARGE_INTEGER Interval; // [sp+C4h] [bp-30h]@1

    UNICODE_STRING Destination; // [sp+D0h] [bp-24h]@1

    OBJECT_ATTRIBUTES ObjectAttributes; // [sp+D8h] [bp-1Ch]@1

    void *Buffer; // [sp+F0h] [bp-4h]@1

    String.Length = 0;

    String.MaximumLength = 0;

    __asm

    {

        mov word ptr String.Buffer + 2, 0

    }

    //HIWORD(String.Buffer) = 0;

    v2[0] = -86;

    v2[1] = 0;

    v2[2] = 0;

    v2[3] = 0;

    v2[4] = 0;

    v2[5] = 0;

    v2[6] = 0;

    v2[7] = 0;

    v2[8] = 62;

    v2[9] = 0;

    v2[10] = 0;

    v2[11] = 0;

    v2[12] = 40;

    v2[13] = 0;

    v2[14] = 0;

    v2[15] = 0;

    v2[16] = 72;

    v2[17] = 0;

    v2[18] = 0;

    v2[19] = 0;

    v2[20] = 9;

    v2[21] = 0;

    v2[22] = 0;

    v2[23] = 0;

    v2[24] = 1;

    v2[25] = 0;

    v2[26] = 1;

    v2[27] = 0;

    v2[28] = 0;

    v2[29] = 0;

    v2[30] = 0;

    v2[31] = 0;

    v2[32] = 108;

    v2[33] = 0;

    v2[34] = 0;

    v2[35] = 0;

    v2[36] = 0;

    v2[37] = 0;

    v2[38] = 0;

    v2[39] = 0;

    v2[40] = 0;

    v2[41] = 0;

    v2[42] = 0;

    v2[43] = 0;

    v2[44] = 0;

    v2[45] = 0;

    v2[46] = 0;

    v2[47] = 0;

    v2[48] = 0;

    v2[49] = 0;

    v2[50] = 0;

    v2[51] = 0;

    v2[52] = 0;

    v2[53] = 0;

    v2[54] = 0;

    v2[55] = 0;

    v2[56] = -1;

    v2[57] = -1;

    v2[58] = -1;

    v2[59] = 0;

    v2[60] = 118;

    v2[61] = 121;

    v2[62] = -98;

    v2[63] = -3;

    v2[64] = -26;

    v2[65] = 55;

    v2[66] = 119;

    v2[67] = 49;

    v2[68] = -80;

    v2[69] = 0;

    v2[70] = 0;

    v2[71] = 0;

    v2[72] = 118;

    v2[73] = -7;

    v2[74] = -98;

    v2[75] = -3;

    v2[76] = -26;

    v2[77] = -73;

    v2[78] = 39;

    v2[79] = 53;

    v2[80] = -65;

    v2[81] = 0;

    v2[82] = 0;

    v2[83] = 0;

    v2[84] = -106;

    v2[85] = -7;

    v2[86] = -98;

    v2[87] = -3;

    v2[88] = -27;

    v2[89] = -73;

    v2[90] = -81;

    v2[91] = 45;

    v2[92] = -65;

    v2[93] = 0;

    v2[94] = 0;

    v2[95] = 0;

    v2[96] = -26;

    v2[97] = -63;

    v2[98] = -128;

    v2[99] = -3;

    v2[100] = -27;

    v2[101] = -73;

    v2[102] = -113;

    v2[103] = 45;

    v2[104] = -80;

    v2[105] = 0;

    v2[106] = 0;

    v2[107] = 0;

    v2[108] = 118;

    v2[109] = -1;

    v2[110] = -127;

    v2[111] = -3;

    v2[112] = -27;

    v2[113] = -105;

    v2[114] = -33;

    v2[115] = 44;

    v2[116] = -65;

    v2[117] = 0;

    v2[118] = 0;

    v2[119] = 0;

    v2[120] = 118;

    v2[121] = -1;

    v2[122] = -98;

    v2[123] = -3;

    v2[124] = -27;

    v2[125] = -41;

    v2[126] = -81;

    v2[127] = 46;

    v2[128] = -65;

    v2[129] = 0;

    v2[130] = 0;

    v2[131] = 0;

    v2[132] = -114;

    v2[133] = -5;

    v2[134] = -98;

    v2[135] = -3;

    v2[136] = -29;

    v2[137] = -41;

    v2[138] = 39;

    v2[139] = 30;

    v2[140] = -65;

    v2[141] = 0;

    v2[142] = 0;

    v2[143] = 0;

    v2[144] = -2;

    v2[145] = 123;

    v2[146] = -98;

    v2[147] = -31;

    v2[148] = -29;

    v2[149] = -41;

    v2[150] = 119;

    v2[151] = 30;

    v2[152] = -65;

    v2[153] = 0;

    v2[154] = 0;

    v2[155] = 0;

    v2[156] = -1;

    v2[157] = 115;

    v2[158] = -100;

    v2[159] = -3;

    v2[160] = -29;

    v2[161] = -58;

    v2[162] = 115;

    v2[163] = 30;

    v2[164] = 63;

    v2[165] = 0;

    v2[166] = 0;

    v2[167] = 0;

    Interval.LowPart = 0xFE363C80u;

    Interval.HighPart = 0xFFFFFFFFu;

    test2(&Value);

    // 申请分页内存

    String.Buffer = (PWSTR)ExAllocatePool(PagedPool, 0x100u);

    String.MaximumLength = 0x100u;

    Destination.Buffer = (PWSTR)ExAllocatePool(PagedPool, 0x200u);

    Destination.MaximumLength = 0x7FFFu;           // 原来是0x7FFF

    v3 = RtlIntegerToUnicodeString(Value, 0x10u, &String);

    RtlAppendUnicodeToString(&Destination, L"\\??\\C:\\windows\\system32\\");

    RtlAppendUnicodeStringToString(&Destination, &String);

    RtlAppendUnicodeToString(&Destination, L".dll");

    ObjectAttributes.Length = 24;

    ObjectAttributes.RootDirectory = 0;

    ObjectAttributes.Attributes = 64;

    ObjectAttributes.ObjectName = &Destination;

    ObjectAttributes.SecurityDescriptor = 0;

    ObjectAttributes.SecurityQualityOfService = 0;

    v3 = ZwCreateFile(&Handle, 0x40000000u, &ObjectAttributes, &IoStatusBlock, 0, 0x80u, 2u, 3u, 0x20u, 0, 0);

    Buffer = ExAllocatePool(PagedPool, 0xA8u);

    memcpy(Buffer, v2, 0xA8u);

    ZwWriteFile(Handle, 0, 0, 0, &IoStatusBlock, Buffer, 0xA8u, 0, 0);

    KeDelayExecutionThread(0, 0, &Interval);

    ZwClose(Handle);

    //ZwDeleteFile(&ObjectAttributes);

    RtlFreeUnicodeString(&String);

    return 0;

}

// DPC例程是运行在DISPATCH_LEVEL级别,因为不能使用分页内存。

// 读写文件就会造成蓝屏 ,读写文件必须是分页内存

BOOLEAN DeferredRoutine(

    IN PKDPC pDpc,

    IN PVOID  DeferredContext,

    IN PVOID  SystemArgument1,

    IN PVOID  SystemArgument2

    )

{

    sub_11780();

    return KeSetTimer(&Timer, DueTime, &dpc);

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegisterPath)

{

    PKDEFERRED_ROUTINE DeferredRoutine;

    sub_11780();

    KeInitializeTimer(&Timer);

    KeInitializeDpc(&dpc, DeferredRoutine, 0);

    DueTime.LowPart = 0xFE363C80u;

    DueTime.HighPart = 0xFFFFFFFFu;

    // 这里只会调用一次DPC例程

    KeSetTimer(&Timer, DueTime, &dpc);

    pDriverObject->DriverUnload = DriverUnload;

    return STATUS_SUCCESS;

}

驱动: Driver.zip

上传的附件 1.png
2.png
3.png
4.png
Driver.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功