;文件:attach.asm.
;宏定义.
_call MACRO procedure, parameters:VARARG
LOCAL param, reversed
reversed TEXTEQU <>
% for param, <parameters>
reversed CATSTR <param>, <!,>, reversed
endm
% for param, <reversed>
push param
endm
call procedure
ENDM
;常量定义.
.const
;代码段开始.
.code
;以“_”开头,并以 API 函数名相接的,是用来贮存通过 GetProcAddress 得到的 API 线形地址.
attach_start equ $
OEP dd 0
hLibUser32 dd ?
_GetProcAddress dd 0
_LoadLibrary dd 0
_FreeLibrary dd 0
_ExitProcess dd 0
_MessageBox dd 0
szLibUser32 db "user32", 0
szProcLoadLibrary db "LoadLibraryA", 0
szProcFreeLibrary db "FreeLibrary", 0
szProcExitProcess db "ExitProcess", 0
szProcMessageBox db "MessageBoxA", 0
_szAppTitle db "Shellcode Test", 0
_szShowText db "Shellcode Done!",0
;真正的代码开始.
attach_code_start equ $
call Attachment
;-----------------------------------------------------------------------------
;附加段的子程序处理模块.
Attachment proc
;以下是经典的查找 kernel32.dll 的基地址的代码.
pop ebp
sub ebp, offset Attachment
mov eax, [esp]
and eax, 0FFFF0000h
@@chk:
cmp dword ptr [eax], 00905A4Dh
je @@fnd
sub eax, 1000h
jmp @@chk
@@fnd:
;以下的涉及到 PE 格式的操作.
push ebp
push ebx
push esi
push edi
mov ebp, eax
add eax, [eax][IMAGE_DOS_HEADER.e_lfanew]
mov edi, [eax][IMAGE_NT_HEADERS.OptionalHeader.DataDirectory]
add edi, ebp
mov esi, [edi][IMAGE_EXPORT_DIRECTORY.AddressOfNames]
add esi, ebp
;在 kernel32.dll 里面查找 GetProcAddress 的API 的线形地址.
xor edx, edx
@@name:
mov eax, [esi]
add eax, ebp
@@chgp: ; GetProcAddress()
cmp dword ptr [eax+00h], "PteG" ; GetP
jne @@next
cmp dword ptr [eax+04h], "Acor" ; rocA
jne @@next
cmp dword ptr [eax+08h], "erdd" ; ddre
jne @@next
cmp word ptr [eax+0Ch], "ss" ; ss
jne @@next
mov eax, [edi][IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
add eax, ebp
movzx ebx, word ptr [edx*2+eax]
mov eax, [edi][IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
add eax, ebp
mov eax, [ebx*4+eax]
add eax, ebp
; 找到GetProcAddress 的线形地址并保存.
mov [_GetProcAddress], eax
@@next:
add esi, 4
inc edx
cmp edx, [edi][IMAGE_EXPORT_DIRECTORY.NumberOfNames]
jne @@name
;下面的是通过 GetProcAddress 获得一些API 的线形地址,并储存起来,供后面使用.
_call [_GetProcAddress], ebp, offset szProcFreeLibrary
mov [_FreeLibrary], eax
_call [_GetProcAddress], ebp, offset szProcExitProcess
mov [_ExitProcess], eax
_call [_GetProcAddress], ebp, offset szProcLoadLibrary
mov [_LoadLibrary], eax
;载入 user32.dll ,并储存它的句柄.
_call eax, offset szLibUser32
mov [hLibUser32], eax
_call [_GetProcAddress], [hLibUser32], offset szProcMessageBox
mov [_MessageBox], eax
;调用加壳函数
_call ShellFunc
;返回原程序入口点
mov eax, dword ptr [OEP]
jmp eax
_call [_FreeLibrary], [hLibUser32]
_call [_ExitProcess], 0
Attachment endp
;-----------------------------------------------------------------------------
;用于加壳的函数
ShellFunc proc
;显示对话框
_call [_MessageBox], 0, offset _szShowText, offset _szAppTitle,\
MB_OK or MB_ICONASTERISK or MB_APPLMODAL
ret
ShellFunc endp
;-----------------------------------------------------------------------------
;计算加壳代码的长度.
attach_size equ $ - offset attach_start
;文件:Shellcode.asm.
.386
.model flat, stdcall
option casemap:none
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\shell32.inc
include c:\masm32\include\comdlg32.inc
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\shell32.lib
includelib c:\masm32\lib\comdlg32.lib
include c:\masm32\include\dialogs.inc
;文本宏定义.
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
;子程序定义.
DlgProc proto :DWORD, :DWORD, :DWORD, :DWORD
ModifyFile proto
ShellProc proto
;常量定义.
.const
IDI_SHELL equ 1000
IDC_FILENAME equ 1001
IDC_FILEOPEN equ 1002
IDC_OK equ 1004
IDC_CANCEL equ 1005
;变量定义.
.data
szFileFilter db "Executables (*.exe)", 0, "*.exe", 0, 0
;插入宿主的代码.
include attach.asm
;未初始化的变量定义.
.data?
mbp MSGBOXPARAMS <>
ofn OPENFILENAME <>
hInstance dd ?
hFile dd ?
szFileName db MAX_PATH dup (?)
szFileNameSave db MAX_PATH dup (?)
szFileNameBak db MAX_PATH dup (?)
img_dos_hdr IMAGE_DOS_HEADER <>
img_nt_hdrs IMAGE_NT_HEADERS <>
img_sect_hdr IMAGE_SECTION_HEADER <>
;代码段开始.
.code
main:
invoke GetModuleHandle, eax
mov hInstance, eax
mov mbp.hInstance, eax
mov ofn.hInstance, eax
Dialog "Shellcode", \
"MS Sans Serif",10, \ ; 字体和字体大小.
WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \ ; 对话框窗口.
5, \ ; 控件数目.
50,50,160,75,\ ; x和y坐标.
1024 ; 内存缓冲区大小.
DlgButton "Quit",WS_TABSTOP,110,40,38,12,IDC_CANCEL
DlgButton "OK", WS_TABSTOP,10,40,35,12,IDC_OK
DlgButton "Open",WS_TABSTOP,110,6,38,12,IDC_FILEOPEN
DlgEdit WS_TABSTOP or WS_BORDER or BS_CENTER,10,20,138,12,IDC_FILENAME
DlgStatic "File Name",SS_LEFT,10,8,70,9,100
CallModalDialog hInstance,0,DlgProc,NULL
invoke ExitProcess,NULL
;-----------------------------------------------------------------------------
;主程序消息循环.
DlgProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
.if uMsg == WM_CLOSE
invoke EndDialog, hWnd, 0
invoke ExitProcess, 0
.elseif uMsg == WM_INITDIALOG
;设置图标.
invoke LoadIcon, hInstance, IDI_SHELL
invoke SendMessage, hWnd, WM_SETICON, NULL, eax
;储存hWnd,后面会用到.
mov eax, hWnd
mov mbp.hwndOwner, eax
mov ofn.hwndOwner, eax
;设置每个 Edit 框的最大文本输入字数.
invoke SendDlgItemMessage, hWnd, IDC_FILENAME, \
EM_SETLIMITTEXT, sizeof szFileName, 0
.elseif uMsg == WM_COMMAND
mov eax, wParam
.if ax == IDC_FILEOPEN
;"打开文件"对话框.
mov ofn.lStructSize, sizeof ofn
mov ofn.lpstrFilter, offset szFileFilter
mov ofn.lpstrFile, offset szFileName
mov ofn.nMaxFile, sizeof szFileName
invoke GetOpenFileName, addr ofn
;如果选择了一个文件,就把它的文件名输出到"文件名"这个 Edit 中.
test eax, eax
.if !zero?
invoke SetDlgItemText, hWnd, IDC_FILENAME, addr szFileName
.endif
.elseif ax == IDC_OK
;进入加壳模块.
invoke ShellProc
;把加壳后的程序变成"test.exe".
invoke CopyFile, addr szFileName, CTEXT("test.exe"),FALSE
;把备份文件还原还原成加壳前的状态.
invoke CopyFile, addr szFileNameBak, addr szFileNameSave,FALSE
;删除备份文件.
invoke DeleteFile,addr szFileNameBak
.elseif ax == IDC_CANCEL
;关闭窗口.
invoke SendMessage, hWnd, WM_CLOSE, 0, 0
invoke ExitProcess, 0
.endif
.else
mov eax, FALSE
ret
.endif
xor eax, eax
ret
DlgProc endp
;-----------------------------------------------------------------------------
;写入加壳节的模块.
ShellProc proc uses ebx ecx edx esi edi
LOCAL bOK: BOOL
invoke GetDlgItemText, [mbp.hwndOwner], IDC_FILENAME, \
addr szFileName, sizeof szFileName
;备份文件.
invoke lstrcpy, addr szFileNameSave, addr szFileName
invoke lstrcpy, addr szFileNameBak, addr szFileName
;把 szFileName字符串变成 szFileNameBak(szFileName.bak).
invoke lstrcat, addr szFileNameBak, CTEXT(".bak")
;把szFileName文件复制为 szFileNamebak文件以作备份.
invoke CopyFile, addr szFileName, addr szFileNameBak, FALSE
invoke ModifyFile
invoke MessageBox, [mbp.hwndOwner], CTEXT("加壳成功!"), \
addr szFileName, MB_OK or MB_ICONINFORMATION
ret
ShellProc endp
;-----------------------------------------------------------------------------
;加壳函数.
ModifyFile proc uses ebx ecx edx esi edi
LOCAL bOK: BOOL
LOCAL pMem:DWORD
;打开文件.
invoke CreateFile, addr szFileName, \
GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, NULL,\
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
;如果打开文件失败,进行处理.
.if eax == INVALID_HANDLE_VALUE
;打开文件失败.
jmp @@safe
.endif
;复制文件句柄.
mov hFile, eax
;定位到文件头.
invoke SetFilePointer,hFile,0,0,FILE_BEGIN
;读入 PE 文件的 IMAGE_DOS_HEADER.
invoke ReadFile, hFile, addr img_dos_hdr, sizeof img_dos_hdr, esp, 0
;判断是否为一个有效的 PE 文件.
cmp [img_dos_hdr.e_magic], "ZM"
.if !zero?
;这不是一个有效的 PE 文件!
jmp @@safe
.endif
;把文件指针指向 IMAGE_NT_HEADERS,并读入该部分内容.
invoke SetFilePointer, hFile, img_dos_hdr.e_lfanew, 0, FILE_BEGIN
invoke ReadFile, hFile, addr img_nt_hdrs, sizeof img_nt_hdrs, esp, 0
;判断是否为一个有效的 PE 文件.
cmp [img_nt_hdrs.Signature], "EP"
.if !zero?
;这不是一个有效的 PE 文件.
jmp @@safe
.endif
;储存一些数据,后面会用到.
xor eax, eax
xor edx, edx
movzx ecx, [img_nt_hdrs.FileHeader.NumberOfSections]
@@s000:
push ecx
push eax
push edx
;读入 IMAGE_SECTION_HEADER 内容.
invoke ReadFile, hFile, addr img_sect_hdr, sizeof img_sect_hdr, esp, 0
;判断是否已被加壳过:
cmp dword ptr[img_sect_hdr.Name1], "SA."
.if eax == 0
;文件已被加壳.
jmp @@safe
.endif
;查找可以插入新节的位置.
pop edx
mov eax, img_sect_hdr.PointerToRawData
add eax, img_sect_hdr.SizeOfRawData
cmp eax, edx
jbe @@s001
mov edx, eax
@@s001:
pop eax
mov ecx, [img_sect_hdr.VirtualAddress]
add ecx, [img_sect_hdr.Misc.VirtualSize]
cmp eax, ecx
jae @@s002
mov eax, ecx
@@s002:
pop ecx
loopd @@s000
;新节的名称为".AS".
mov dword ptr [img_sect_hdr.Name1+00h], "SA."
;填充剩下的字段:
mov [img_sect_hdr.Misc.VirtualSize], attach_size
mov [img_sect_hdr.VirtualAddress], eax
mov [img_sect_hdr.SizeOfRawData], attach_size
mov [img_sect_hdr.PointerToRawData], edx
mov [img_sect_hdr.PointerToRelocations], ecx
mov [img_sect_hdr.PointerToLinenumbers], ecx
mov dword ptr [img_sect_hdr.NumberOfRelocations], ecx
;计算新节的加载RVA.
mov edx, 00000FFFh
test [img_sect_hdr.VirtualAddress], edx
.if !zero?
and edx, [img_sect_hdr.VirtualAddress]
sub edx, 1000h
neg edx
add [img_sect_hdr.VirtualAddress], edx
.endif
;计算新节的 PointerToRawData 的偏移值.在 Win2k/XP 中,200h是比较保险的值.
xor edx, edx
mov eax, [img_sect_hdr.PointerToRawData]
mov ecx, 200h
div ecx
test edx, edx
.if !zero?
sub edx, 200h
neg edx
add [img_sect_hdr.PointerToRawData], edx
.endif
;设置新节的属性.
;code/data/execute/read/write/inited data/un-inited data.
mov [img_sect_hdr.Characteristics], 0E00000E0h
;把新节信息(IMAGE_SECTION_HEADER)写入文件.
invoke WriteFile, [hFile], addr img_sect_hdr, sizeof img_sect_hdr, esp, 0
;把一些有用的信息压栈,后面会用到.
push esi
push edi
push eax
;分配内存.
invoke GlobalAlloc,GMEM_FIXED,attach_size
mov pMem,eax
mov esi, attach_start
mov edi, pMem
mov ecx, attach_size
rep movsb
mov esi, pMem
mov ecx, attach_size
;改写原程序的代码段的第一条指令的入口地址.
@@copy:
mov eax, [esi]
and eax, NOT 00000FFFh
cmp eax, attach_start
.if zero?
mov eax, [esi]
sub eax, attach_start
add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
add eax, [img_sect_hdr.VirtualAddress]
mov [esi], eax
.endif
inc esi
loopd @@copy
mov eax, [img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
mov ebx, pMem
add ebx, OEP-attach_start
mov dword ptr[ebx],eax
;定位到新节的起始偏移地址.
invoke SetFilePointer, [hFile], [img_sect_hdr.PointerToRawData], 0, FILE_BEGIN
;真正把整个新节的内容写入原程序.
invoke WriteFile, [hFile], pMem, [img_sect_hdr.Misc.VirtualSize], esp, 0
push pMem
;释放内存.
call GlobalFree
mov eax, [img_sect_hdr.VirtualAddress]
add eax, attach_code_start - attach_start
inc [img_nt_hdrs.FileHeader.NumberOfSections]
mov [img_nt_hdrs.OptionalHeader.AddressOfEntryPoint], eax
add [img_nt_hdrs.OptionalHeader.SizeOfImage], attach_size
;下面两句非常重要,否则加壳后的程序在 Win2k 以上的系统中运行会有错误.
push 0
pop [img_nt_hdrs.OptionalHeader.DataDirectory(88).VirtualAddress]
invoke SetFilePointer, [hFile], [img_dos_hdr.e_lfanew], 0, FILE_BEGIN
invoke WriteFile, [hFile], addr img_nt_hdrs, sizeof img_nt_hdrs, esp, 0
;安全的文件关闭点.
@@safe:
invoke CloseHandle, [hFile]
ret
ModifyFile endp
end main

