Why do I get strange result for GetProcAddress for certain executable file name?

Started by jiucenglou, July 20, 2017, 11:33:21 PM

Previous topic - Next topic

jiucenglou

I am learning to get the address of CreateFileW using GetProcAddress.
The result is different if the executable is named differently, for example, "Patch3.exe" or "NoImport.exe".
However, either name gives the same address of other functions such as WriteProcessMemory.
Please have a look at the GIF image in the attached zip.

Could you help to comment what could possibly be the reason... O_O
Many thanks !

PS: The OS is Windows 10 x64 Creators.

_GetKernel.asm

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 3rd Edition>
; by 罗云彬, http://www.win32asm.com.cn
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 公用模块:_GetKernel.asm
; 根据程序被调用的时候堆栈中有个用于 Ret 的地址指向 Kernel32.dll
; 而从内存中扫描并获取 Kernel32.dll 的基址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 错误 Handler
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_SEHHandler proc C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext

pushad
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
mov eax,_lpSEH
push [eax + 0ch]
pop [edi].regEbp
push [eax + 8]
pop [edi].regEip
push eax
pop [edi].regEsp
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution
ret

_SEHHandler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 在内存中扫描 Kernel32.dll 的基址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetKernelBase proc _dwKernelRet
local @dwReturn

pushad
mov @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
call @F
@@:
pop ebx
sub ebx,offset @B
;********************************************************************
; 创建用于错误处理的 SEH 结构
;********************************************************************
assume fs:nothing
push ebp
lea eax,[ebx + offset _PageError]
push eax
lea eax,[ebx + offset _SEHHandler]
push eax
push fs:[0]
mov fs:[0],esp
;********************************************************************
; 查找 Kernel32.dll 的基地址
;********************************************************************
mov edi,_dwKernelRet
and edi,0ffff0000h
.while TRUE
.if word ptr [edi] == IMAGE_DOS_SIGNATURE
mov esi,edi
add esi,[esi+003ch]
.if word ptr [esi] == IMAGE_NT_SIGNATURE
mov @dwReturn,edi
.break
.endif
.endif
_PageError:
sub edi,010000h
.break .if edi < 070000000h
.endw
pop fs:[0]
add esp,0ch
popad
mov eax,@dwReturn
ret

_GetKernelBase endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 从内存中模块的导出表中获取某个 API 的入口地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetApi proc _hModule,_lpszApi
local @dwReturn,@dwStringLength

pushad
mov @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
call @F
@@:
pop ebx
sub ebx,offset @B
;********************************************************************
; 创建用于错误处理的 SEH 结构
;********************************************************************
assume fs:nothing
push ebp
lea eax,[ebx + offset _Error]
push eax
lea eax,[ebx + offset _SEHHandler]
push eax
push fs:[0]
mov fs:[0],esp
;********************************************************************
; 计算 API 字符串的长度(带尾部的0)
;********************************************************************
mov edi,_lpszApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpszApi
mov @dwStringLength,ecx
;********************************************************************
; 从 PE 文件头的数据目录获取导出表地址
;********************************************************************
mov esi,_hModule
add esi,[esi + 3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY
;********************************************************************
; 查找符合名称的导出函数名
;********************************************************************
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpszApi
mov ecx,@dwStringLength
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx >= [esi].NumberOfNames
jmp _Error
@@:
;********************************************************************
; API名称索引 --> 序号索引 --> 地址索引
;********************************************************************
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule
;********************************************************************
; 从地址表得到导出函数地址
;********************************************************************
mov eax,[eax]
add eax,_hModule
mov @dwReturn,eax
_Error:
pop fs:[0]
add esp,0ch
assume esi:nothing
popad
mov eax,@dwReturn
ret

_GetApi endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



NoImport.asm

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 基于 <琢石成器> 第17章 例子 Noimport.asm:
; 以从内存中动态获取的办法使用 API
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff NoImport.asm
; Link /subsystem:windows NoImport.com
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .386
        .model flat, stdcall
        option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include     windows.inc
include     user32.inc
include     kernel32.inc
includelib  user32.lib
includelib  kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 一些函数的原形定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProtoGetProcAddress    typedef proto   :dword,:dword
_ProtoLoadLibrary   typedef proto   :dword
_ProtoCreateFileW   typedef proto   :dword,:dword,:dword,:dword,:dword,:dword,:dword
_ApiGetProcAddress  typedef ptr _ProtoGetProcAddress
_ApiLoadLibrary     typedef ptr _ProtoLoadLibrary
_ApiCreateFileW     typedef ptr _ProtoCreateFileW
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
PATCH_POSITION  equ 0043FE40h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .data
hDllKernel32      dd                  0
hDllKernelBase    dd                  0
_GetProcAddress   _ApiGetProcAddress  0
_LoadLibrary      _ApiLoadLibrary     0
_CreateFileW      _ApiCreateFileW     0

        .data?
szBuffer          db 1024 dup (?)           
 
        .const
szGetProcAddress  db  'GetProcAddress',0
szLoadLibrary     db  'LoadLibraryA',0
szKernelBase      db  'KernelBase',0
szCreateFileW     db  'CreateFileW',0
;szCreateFileW     db  'CreateFileMappingW',0
;szCreateFileW     db  'WriteProcessMemory',0
szCreateFileWAddr db  'Address: %08x',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .code
include     _GetKernel.asm
Start:
;********************************************************************
; 从堆栈中的 Ret 地址转换 Kernel32.dll 的基址,并在 Kernel32.dll
; 的导出表中查找 GetProcAddress 函数的入口地址
;********************************************************************
        invoke  _GetKernelBase,[esp]    ;获取Kernel32.dll基址
        .if eax
            mov hDllKernel32,eax
            invoke  _GetApi,hDllKernel32,addr szGetProcAddress
            mov _GetProcAddress,eax
        .endif
;********************************************************************
; 用得到的 GetProcAddress 函数得到 LoadLibrary 函数地址,
; 装入 KernelBase 得到 CreateFileW 函数地址
;********************************************************************
        .if _GetProcAddress
            invoke  _GetProcAddress,hDllKernel32,addr szLoadLibrary
            mov _LoadLibrary,eax
            .if eax
                invoke  _LoadLibrary,addr szKernelBase
                mov hDllKernelBase,eax
                invoke  _GetProcAddress,hDllKernelBase,addr szCreateFileW
                mov _CreateFileW,eax
                invoke  wsprintf,addr szBuffer,addr szCreateFileWAddr,_CreateFileW
                invoke MessageBox,NULL,offset szBuffer,NULL,MB_OK
            .endif
        .endif
        invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        end Start

aw27

Quote from: jiucenglou on July 20, 2017, 11:33:21 PM
The result is different if the executable is named differently, for example, "Patch3.exe" or "NoImport.exe".


The address is the same. It is just an antivirus reaction. :icon_mrgreen:
Files called patch*.exe are meat for AV.

What program do you use to make animated gifs?

jiucenglou

Thank you for your efforts to help !
Could you help to comment why the addresses are the same, when they contain different numerical values ? :D

GifCam is used for .gif.

aw27

Quote from: jiucenglou on July 21, 2017, 01:06:00 AM
Thank you for your efforts to help !
Could you help to comment why the address is the same, when they contain different numerical values ? :D

Your AV changed the address for you, mine did not but blocked the execution afterwards.

Quote
GifCam is used for .gif.

Very cool this little software.

jiucenglou


aw27