format PE GUI 4.0
entry start

include 'win32w.inc'

AntiDebug equ ; It's more difficult to debug, then jumps goes not to the begin of the function. But any way OllyDbg doesn't show it as usual.

macro rol32 op1, op2
 { match =dword v, op1 \{ v = ((v shl op2) or (v shr (32 - op2))) and $FFFFFFFF \}
   match =word v,  op1 \{ v = ((v shl op2) or (v shr (32 - op2))) and $FFFFFFFF \}
   match =byte v,  op1 \{ v = ((v shl op2) or (v shr (32 - op2))) and $FFFFFFFF \} }

macro iprc [proc, name]
 { forward
    if used proc | impanyway eq
     if name eqtype ''
      local ch
      local hash
      local length
      virtual at 0
       db name
       length = $
       hash = 0
       repeat length
	load ch byte from length-%
	rol32 dword hash, 5
	hash = hash xor (ch and 11111b)
       end repeat
      end virtual
      label proc dword
      db length ; Length, if $ff then load lib, if $fe then end, if $fd then by id
      dd hash
     else
      db $fd
      dd name+1
     end if
    end if }

macro iprcex [proc]
 { forward
    if used proc | proc eq LoadLibraryA | impanyway eq
      local ch
      local hash
      local length
      virtual at 0
       db `proc#''
       length = $
       hash = 0
       repeat length
	load ch byte from length-%
	hash = ((hash shl 5) or (hash shr (32 - 5))) and $FFFFFFFF ; hash = hash rol 5
	hash = hash xor (ch and 11111b)
       end repeat
      end virtual
      virtual at $
       proc dd ?
      end virtual
      db length ; Length, if $ff then load lib, if $fe then end, if $fd then by id
      dd hash
    end if }

macro hip [proc, len, hash]
 { forward
    if used proc | proc eq LoadLibraryA | impanyway eq
     proc db len
	  dd hash
    end if }

macro imod [module, str]
 { forward
    db $fe
    module dd module#.str - $
    module#.text equ str }

macro istr [module]
 { forward
    module#.str db module#.text, 0 }

macro endi ierrproc
 { db $ff }

struct IED
 Characteristics	dd ? ;This field appears to be unused and is always set to 0.
 TimeDateStamp		dd ? ;The time/date stamp indicating when this file was created.
 Version		dd ? ;These fields appear to be unused and are set to 0.
 Name			dd ? ;The RVA of an ASCIIZ string with the name of this DLL.
 Base			dd ? ;The starting ordinal number for exported functions. For example, if the file exports functions with ordinal values of 10, 11, and 12, this field contains 10. To obtain the exported ordinal for a function, you need to add this value to the appropriate element of the AddressOfNameOrdinals array.
 NumberOfFunctions	dd ? ;The number of elements in the AddressOfFunctions array. This value is also the number of functions exported by this module. Theoretically, this value could be different than the NumberOfNames field (next), but actually they're always the same.
 NumberOfNames		dd ? ;The number of elements in the AddressOfNames array. This value seems always to be identical to the NumberOfFunctions field, and so is the number of exported functions.
 AddressOfFunctions	dd ? ;This field is an RVA and points to an array of function addresses. The function addresses are the entry points (RVAs) for each exported function in this module.
 AddressOfNames 	dd ? ;This field is an RVA and points to an array of string pointers. The strings are the names of the exported functions in this module.
 AddressOfNameOrdinals	dd ? ;This field is an RVA and points to an array of WORDs. The WORDs are the export ordinals of all the exported functions in this module. However, don't forget to add in the starting ordinal number specified in the Base field.
ends

proc ProcIdByHash, base, hash, len
	xchg	edi, [base]
	push	ebx ecx edx esi

	mov	ax, 'MZ'
	cmp	[edi], ax
	jz	.end

	mov	ebx, [edi+$3C] ; OffSet to PE Header

	mov	ax, 'PE'
	cmp	[edi+ebx], ax
	jz	.end

	mov	ebx, [edi+ebx+$78] ; Offset to Export section
	test	ebx, ebx
	jz	.noexport

	push	ebx
	mov	ecx, [edi+ebx+IED.NumberOfNames] ; NumberOfFunctions
	mov	ebx, [edi+ebx+IED.AddressOfNames]
	add	ebx, edi

  .next:mov	esi, [ebx+ecx*4-4]
	add	esi, edi
	mov	edx, [hash]
	movsx	eax, byte[len]
	cmp	byte[esi+eax], 0
	jne	.wrng
  @@:	lodsb
	or	al, al
	jz	@f
	and	al, 11111b
	xor	dl, al
	ror	edx, 5
	jmp	@b
  @@:	or	edx, edx
	jz	.ret ; @f
  .wrng:loop	.next
	pop	eax
	xor	eax, eax
	jmp	.end
  .ret: pop	ebx
	mov	eax, [edi+ebx+IED.AddressOfNameOrdinals]
	add	eax, edi
	movzx	eax, word[eax+ecx*2-2]
	add	eax, [edi+ebx+IED.Base]

	test	eax, eax

  .end: pop	esi edx ecx ebx
	mov	edi, [base]
	ret

  .noexport:
	mov	ax, 'NE'
	jmp	.end
endp

proc ProcAddrById, base, id
	xchg	edi, [base]
	xchg	ebx, [id]
	push	edx ecx esi

	mov	ecx, [edi+$3C] ; OffSet to PE Header
	mov	eax, [edi+ecx+$78] ; Offset to Export section
	sub	ebx, [edi+eax+IED.Base]
	mov	esi, [edi+eax+IED.AddressOfFunctions]

	add	esi, edi

	mov	esi, [esi+ebx*4]
	lea	eax, [esi+edi]

; If you don't need Forwarded Export Support you can comment next block
	sub	esi, [edi+ecx+$78]
	cmp	esi, [edi+ecx+$7C]
	ja	@f
	call	GetForwardedProcId
	stdcall ProcAddrById, edi, eax
@@: ; End of block

	pop	esi ecx edx
	mov	ebx, [id]
	mov	edi, [base]
	ret
endp

MAX_MOD_PROC_AND_NAME_LEN = 64

proc GetForwardedProcId
	mov	esi, eax
	mov	ebx, eax

	mov	ecx, MAX_MOD_PROC_AND_NAME_LEN
	sub	esp, ecx

	mov	edx, esp

	push	esi
.loop:	lodsb

	cmp	al, '.'
	jne	@f
	lea	ebx, [edx+1]
@@:
	mov	[edx], al
	inc	edx

	or	al, al
	jz	@f

	loop	.loop
@@:	pop	esi

	cmp	esi, ebx
	jz	.GetProc

	mov	byte[ebx-1], 0
	stdcall LoadLibraryA, esp
	mov	edi, eax

.GetProc:
	add	esp, MAX_MOD_PROC_AND_NAME_LEN

	mov	esi, ebx
	neg	ebx

	xor	edx, edx

@@:	lodsb
	or	al, al
	jz	@f
	and	al, 11111b
	xor	dl, al
	ror	edx, 5
	jmp	@b
@@:
	lea	ebx, [ebx+esi-1]

	lea	ecx, [ebx*5]
	rol	edx, cl

	stdcall ProcIdByHash, edi, edx, ebx

	ret
endp

proc GetKernel
	xor	eax, eax
	mov	eax, [fs:eax+30h]
	test	eax, eax
	js	ngk
	mov	eax, [eax+0Ch]
	mov	esi, [eax+1Ch]
	lodsd
	mov	eax, [eax+8]
	jmp	egk
ngk:	mov	eax, [eax+34h]
	add	eax, 7Ch
	mov	eax, [eax+3Ch]
egk:	ret
endp

proc BaseByAddr, addr
	mov	eax, [addr]

	xor	ax, ax
  @@:	cmp	word[eax], 'MZ'
	jz	@f
	sub	eax, $10000
	jmp	@b
  @@:	ret
endp

proc importer, kernel, imports, loadlib, errproc
	xchg	esi, [imports]
	xchg	edi, [kernel]

	;stdcall BaseByAddr, edi
	;mov     edi, eax

  .loop:lodsb
	cmp	al, $fd
	ja	.more
	je	.byid
	mov	ah, al

	or	edi, edi
	jz	.xxx

	stdcall ProcIdByHash, edi, [esi], [esi-1]

	or	eax, eax
	jnz	 @f
	mov	eax, [errproc]
	jmp	.stor
  @@:
  .gbi: stdcall ProcAddrById, edi, eax
	or	eax, eax
	jnz	 @f
	mov	eax, [errproc]
  @@:

  .stor:if	AntiDebug eq
	 cmp	 word[eax], $FF8B
	 jnz	 @f
	 add	 eax, 2
  @@:	end	if
	 sub	 eax, 4

  @@:	sub	eax, esi
	mov	byte[esi-1], $E9
	mov	dword[esi], eax
  .xxx: lodsd
	jmp	.loop

  .byid:mov	eax, [esi]
	jmp	.gbi

  .more:cmp	al, $ff
	je	.endi
	lodsd

	lea	eax, [eax+esi-4]
	invoke	loadlib, eax
	mov	edi, eax
	mov	[esi-4], eax

	jmp	.loop

  .endi:mov	edi, [kernel]
	mov	esi, [imports]
	ret
endp

proc ImportErrProc
	stdcall MessageBoxA, 0, wfmsg, wferr, MB_ICONERROR
	ret
endp

myi:
  iprc LoadLibraryA, 'LoadLibraryA',\
    ExitProcess,'ExitProcess'
  imod user, 'user32'
  iprcex MessageBoxA,\ ; iprcex if a simbol equal to the name
    WrongFunc
  endi

start:
	stdcall BaseByAddr, [esp]
	;stdcall GetKernel
	stdcall importer, eax, myi, LoadLibraryA, ImportErrProc

	stdcall WrongFunc ; Example of wrong function

	stdcall MessageBoxA, 0, txt, txt, 0

	stdcall ExitProcess, 0
	ret

txt		db "It works",0
wferr		db 'Error',0
wfmsg		db "You'r trying to call wrong function, if it has any arguments then process needs to be restarted.",0
	istr	user