学习 x64 汇编

开发环境:vs 2019 c工程里面 添加asm 文件,执行64位汇编代码。

代码做了 点什么:

1,通过gs寄存器获取模块基地址

2,通过基地址获取导出函数----api 地址

3,通过api做点其他的事情

4,关于ROP的实验

参考:

1,通过gs 寄存器获取模块基地址 Windows x64位通过PEB获得Kernel32基地址 - ciyze - 博客园

2,64位汇编 传参 特点   vc在x64体系的一般传参数方式_weixin_30725315的博客-CSDN博客

3,通过汇编解析pe文件得到LoadLibraryA地址后,加载dll导致0xc000005(这个问题偶尔出现,测试是在1909上没有发现,在22000上出现)。原因是stack 要8字节对齐,​​​​​​https://stackoverflow.com/questions/32160792/loadlibrarya-with-user32-dll-crash-in-ntdll-dll-x64-assemblyhttps://stackoverflow.com/questions/32160792/loadlibrarya-with-user32-dll-crash-in-ntdll-dll-x64-assembly

  (2022/03/31)发现这个问题是自己定义的函数体中栈对其的标准不一致,有的是sub rsp,128h,

有的是sub rsp,120h;统一之后函数都能正常调用。在10240,18363,22000上都测试可运行。

asm 文件

EXTERN numb:DQ
EXTERN GetFib:PROC
.DATA
data db 48h,8bh,0c4h,0fah,48h,83h,0ech,10h,50h,09ch,6ah,10h,48h,8dh
 
kernel32Base dq 0h
ws2_32Base dq 0h
 
ws2_32_name db 'ws2_32.dll',0h,0h,0h,0h
 
aOutputDebugStringA db 'OutputDebugStringA',0h,0h
fOutputDebugStringA dq 0h
 
aLoadLibraryA db 'LoadLibraryA',0h
fLoadLibraryA dq 0h    
 
 
;file operation functions 
logFileName db 'c:\llo.log',0h,0h,0h
wlogFileName dw 63h,3ah,5ch,6ch,6ch,6fh,2eh,6ch,6fh,67h,0h,0h,0h
logFileIsDeleted db 'file_is_deleted!',0h,0h,0h
 
aCreateFile2 db 'CreateFile2',0h,0h,0h
aCreateFileA db 'CreateFileA',0h,0h,0h
aCreateFileW db 'CreateFileW',0h,0h
fCreateFileW dq 0h
fCreateFileA dq 0h
 
aWriteFile db 'WriteFile',0h,0h
fWriteFile dq 0h

aDeleteFile db 'DeleteFileA',0h,0h,0h   ;DeleteFIleA(FilePath);
fDeleteFile dq 0h
 
aCloseHandle db 'CloseHandle',0h,0h
fCloseHandle dq 0h
 
 
aGetLastError db 'GetLastError',0h,0h
fGetLastError dq 0h
 
.CODE
 
;get string length
;rdi points to the string
	;lea  rdi,OutputDebugStringA
	;call strlen
strlen PROC
    push   rdi
	push   rcx
	xor    rcx,rcx
	mov    ecx,0ffffffffh
	xor    eax,eax
	repnz  scasb
	not    ecx
	dec    ecx
	mov    eax,ecx
	pop    rcx
	pop    rdi
    ret
strlen ENDP
 
 
;rdi and rsi the string to compare
;rcx ,length of rsi 
strcmp PROC
    push rbx
	xor  rbx,rbx
	test rcx,rcx
	jz   return
loo:
	mov  bl,byte ptr [rsi+rcx]
	cmp  bl,byte ptr [rdi+rcx]
	jnz  return
	dec  rcx
	jge  loo
	inc  rcx     ;set rcx to zero,and indicates the same of strings
return:
	pop  rbx
    ret
strcmp ENDP
 
 
;return kernel32 base in rbx,if eax==1,get it ;else fails to.
GetKernel32Base PROC
   push   rbx
   push   rdx
   push   r9
   xor    rcx,rcx
   mov    rbx,gs:[60h]
   test   rbx,rbx
   jz     return 
   mov    rbx,qword ptr [rbx+18h]
   test   rbx,rbx
   jz     return 
   mov    rbx,qword ptr [rbx+30h]
   test   rbx,rbx
   jz     return
search_kernel32:
   inc    rcx
   mov    r9,rbx
   add    r9,38h
   mov    dx,word ptr [r9]
   cmp    dx,18h                ;kernel32.dll   ,wide char ,length is 0x18
   jnz    next_one
   mov    r9,qword ptr [r9+8h]
   mov    edx,dword ptr [r9+0ch]
   cmp    edx,320033h          ;WIDE CHAR '32'  in memory is [32 00 33 00]
   jz     tt
next_one:
   mov    rbx,qword ptr [rbx]    ;;ListEntry->Flink
   test   rbx,rbx
   jnz    search_kernel32
   xor    rax,rax               ;set rax to zero ,fails to get kernel32 base
   jmp    return
tt:
   mov    rbx,qword ptr [rbx+10h]
   mov    kernel32Base,rbx
   mov    rax,1 
return:
   pop    r9
   pop    rdx
   pop    rbx
   ret
GetKernel32Base ENDP
 
 ;rbx is the module base
 ;rsi points to the function name
GetProcAddressByName PROC
	;int 3
    	mov    rax,rbx              ;rbx is the module base
 
		mov    bx,word ptr [rax]
		xor    rdx,rdx              ;set rdx to zero
		xor    rcx,rcx
		cmp    bx,5a4dh            ;MZ标示
 
		jnz    retu
 
		mov    ebx,dword ptr [rax+3ch];获取PE头偏移
 
		test   ebx,ebx
		jz     retu
 
		mov    ecx,dword ptr [rax+rbx]
		cmp    ecx,4550h;PE标示
		jnz    retu
 
		;直接读的结构体里面的偏移,这个用winDbg看可能比较直观一点
find:
        xor     rdx,rdx
		xor     rcx,rcx
		mov     edx,dword ptr [rax+rbx+88h];因为模块已经加载到内存,这里可以直接用这个偏移加模块基址,和从本地文件读取有点差别
 
		mov     ecx,dword ptr [rax+rdx+18h];ImageExportDirectory.NumberOfNames
 
 
		mov     edx,dword ptr [rax+rdx+20h];ImageExportDirectory.AddressOfNames;存函数名称字符串的偏移,这里相当于一个数组
 
		push    rbx
 
		push    rcx
 
		add     rdx,rax;加上基址
		;lea     rbx,sLoadLibraryA
		;mov     rsi,rbx
		;the rsi points to the function name string.
		xor     rbx,rbx
find_func_name:
		push    rax
		mov     rdi,rsi
        call    strlen          ;mov     ecx,0ch
		mov     ecx,eax
		pop     rax
 
		xor     rdi,rdi
		mov     edi,dword ptr [rdx+4*rbx];从字符串数组中取值比较
		push    rsi
		add     rdi,rax
 
		;repe    cmpsb   ;字符串循环比较,ecx为0或不等,结束比较
		call    strcmp
		test    ecx,ecx
 
		jz      get_func
		pop     rsi
		inc     ebx
 
		pop     rcx
 
		cmp     ebx,ecx
 
		push    rcx
		jl      find_func_name
		jmp     search_done
 
get_func:
		mov     edi,ebx
		pop     rsi
		pop     rcx
 
		pop     rbx
		xor     rdx,rdx
		xor     rcx,rcx
		mov     edx,dword ptr [rax+rbx+88h];
		
		mov     edx,dword ptr [rax+rdx+1ch];ImageExportDirectory.AddressofFunctions
 
		add     rdx,rax
		mov     ecx,dword ptr [rdx+rdi*4];从函数地址数组中取值(是偏移)
 
 
		add     rcx,rax
		mov     rbx,rcx
		jmp     retu
 
search_done:
		pop    rcx
		pop    rbx
retu:
	    mov    rax,rbx
    ret
GetProcAddressByName ENDP
 
mm PROC
    sub  rsp,128h             ;amazing!  use 'sub rsp,28h' to expand the local stack,and the code do not crash!
    call GetKernel32Base       ;base address is in rbx,
    test eax,eax
    jz   return
 
	lea  rsi,aLoadLibraryA
	mov  rbx,kernel32Base
    call GetProcAddressByName
	test rax,rax
	jz   return
    mov  fLoadLibraryA,rax
 
	lea  rsi,aOutputDebugStringA
	mov  rbx,kernel32Base
	call GetProcAddressByName
	test rax,rax
	jz   return
	mov  fOutputDebugStringA,rax
 
	lea  rsi,aCreateFileA
	mov  rbx,kernel32Base
	call GetProcAddressByName
	test rax,rax
	jz   return
	mov  fCreateFileA,rax
 
	lea  rsi,aWriteFile
	mov  rbx,kernel32Base
	call GetProcAddressByName
	test rax,rax
	jz   return
	mov  fWriteFile,rax
 
    lea  rsi,aDeleteFile
	mov  rbx,kernel32Base
	call GetProcAddressByName
	test  rax,rax
	jz   return
	mov  fDeleteFile,rax

	lea rsi,aCloseHandle
	mov rbx,kernel32Base
	call GetProcAddressByName
	test rax,rax
	jz   return 
	mov  fCloseHandle,rax 
 
	lea  rsi,aGetLastError
	mov  rbx,kernel32Base
	call GetProcAddressByName 
	test rax,rax
	jz   return 
	mov  fGetLastError,rax
 
    lea   rsi,aCreateFileW
	mov   rbx,kernel32Base
	call  GetProcAddressByName
	test  rax,rax
	jz    return
	mov   fCreateFileW,rax

	lea  rcx,ws2_32_name
	call fLoadLibraryA
	mov  ws2_32Base,rax
 
return:
    add rsp,128h
    ret
 
mm ENDP
 
file_op PROC
    sub   rsp,128h
	
	lea   rcx,wlogFileName           ;1
	mov   rdx,0c0000000h            ;2 GENERIC_READ|GENERIC_WRITE
	mov   r8,1                      ;3 FILE_SHARE_READ
	mov   r9,0                      ;4
	                                ;the rest parameters move into stack
	mov  qword ptr [rsp+20h],1      ;5
	mov  qword ptr [rsp+28h],80h    ;6
	mov  qword ptr [rsp+30h],0      ;7
 
	call fCreateFileW    ;create a new file with FileName
 
	test  rax,rax
	js    return
	;
	;do read/write file
	;
	mov  rsi,rax
	mov  rcx,rax
	lea  rdx,aCreateFileA
	mov  r8,7h
	lea  r9,aCreateFileA

	mov qword ptr[rsp+20h],0
	call fWriteFile          ;write something into file
	;call  fGetLastError
	;close handle
	mov   rcx,rsi
	call  fCloseHandle;close file handle

return:
   ; call  fGetLastError

	;delete file
	
	lea   rcx,logFileName
	call  fDeleteFile
	lea   rcx,logFileIsDeleted
	call  cOutputDebugStringA

	add   rsp,128h
    ret
file_op ENDP
 
 ;jz
 ;returns a number
 ;CheckJz() will return 123
 ;after add dl,dl
 ;the zero flag will be set to true
 CheckJz PROC
    mov   dl,080h
	add   dl,dl
	jnz    l_not_zero
	mov   rax,123
	jmp   l_return
l_not_zero:
    mov   rax,111
l_return:
	ret
CheckJz ENDP

cOutputDebugStringA PROC
    sub   rsp,128h
	mov   rax,fOutputDebugStringA
	cmp   rax,0
	jbe   l_return
	;lea   rsi,aOutputDebugStringA
	;mov   rcx,rsi
	call  fOutputDebugStringA
l_return:
    add   rsp,128h
	ret
cOutputDebugStringA ENDP

;play with rop gadgets
;
;
LittleRop_set_eax PROC
   pop    rax;pop out return address
   pop    rax
   ret
LittleRop_set_eax ENDP

LittleRop_set_ebx PROC
   pop   rbx
   pop   rbx
   ret
LittleRop_set_ebx ENDP

LittleRop_set_ecx PROC
   pop   rcx
   pop   rcx
   ret
LittleRop_set_ecx ENDP

LittleRop_set_edx PROC
   push   rcx
   ret
LittleRop_set_edx ENDP

; http://expdev-kiuhnm.rhcloud.com - 133 -
;By now it should be clear why this technique is called ROP: the instruction RET is used to jump from one
;piece of code to the next. The pieces of code are usually called gadgets. A gadget is just a sequence of
;instructions which ends with a RET instruction.
;The hard part is finding and chaining together the right gadgets to achieve our goals
PlayRop PROC
  sub    rsp,128h

   mov   rdx,rcx;保存rcx,跳转地址
   ;push   00000000h
   ;push   11111111h
   lea    rax,offset loc_ret
   push   rax
   push   33333333h

   lea    rax,offset loc_call_set_ecx
   push   rax
   push   44444444h

   lea    rax,offset loc_call_set_ebx
   push   rax
   push   55555555h
   ;call LittleRop_set_eax
   call LittleRop_set_eax ;eax=0x55555555
loc_call_set_ebx:
   ;call LittleRop_set_ebx
   call LittleRop_set_ebx;ebx=0x44444444
loc_call_set_ecx:
   ;call LittleRop_set_ecx
   call  LittleRop_set_ecx;ecx=0x33333333
loc_ret:
    ;call int 3 to interrupt the debugger to see register data
   ;int 3
   mov   rcx,rdx;跳转地址作为参数
   call LittleRop_set_edx
  add   rsp,128h
  ret
PlayRop ENDP

;https://stackoverflow.com/questions/32160792/loadlibrarya-with-user32-dll-crash-in-ntdll-dll-x64-assembly
;
;有的函数中用sub rsp,120h,有的函数中用sub rsp,128h
;导致冲突,应该与最开始的一个sub rsp,保持一直;,sub rsp,128h
;
;
setnum PROC
    ;INT 3
    sub   rsp,128h     ; NOTE: The stack needs to be 16 byte aligned and starts out
                       ; 8 byte aligned

	lea  rcx,offset loc_work
	call PlayRop  ;执行PlayRop会将执行流程衔接到loc_work,跳过下面的'jmp loc_setnum_ret’指令

	jmp loc_setnum_ret
loc_work:
	pop   rcx ;平衡stack,上面有个push rcx没有对应的pop
	;add   rsp,128h
    mov   numb,12345678h
    call  mm
   
	;load ws2_32.dll
	lea  rcx,ws2_32_name
	call fLoadLibraryA
	mov  ws2_32Base,rax

	lea   rsi,ws2_32_name
	mov   rcx,rsi
    call  cOutputDebugStringA

	lea   rsi,logFileName
	mov   rcx,rsi
    call  cOutputDebugStringA

	call  file_op
 
    mov   rcx,9
	call  GetFib
	mov   numb,rax

loc_setnum_ret:
	add   rsp,128h
	ret
setnum ENDP
 
END

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值