九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
匯編中的字符串操作指令
  每一種語言都有一些字符串操作函數(shù),反匯編后的代碼也不例外。網(wǎng)上講的都比較零碎,我將它們收集起來,并配上自己的理解,形成本文。

 

一、字節(jié)操作指令:lodsb和stosb

1. lodsd需要寄存器esi配合使用。每執(zhí)行一次lodsb,就將[esi]中的一個字節(jié)復(fù)制到al寄存器中。

    即:lodsd == [esi] --> al

 

2. stosb需要寄存器edi配合使用。每執(zhí)行一次stosb,就將al中的內(nèi)容復(fù)制到[edi]中。

    即:stosb == al --> [edi]

 

3. ecx和cld指令。以上兩條指令,一次只能復(fù)制一個字節(jié)。要是有多個字節(jié)需要復(fù)制該怎么辦呢?那就需要用到一個計數(shù)器,所以常用ecx保存需要復(fù)制的字節(jié)個數(shù)。

為了能夠自動復(fù)制,esi和edi需要能夠自動的遞增或者遞減。這就用到了DF標(biāo)志位(Directory Flag)。DF=0,esi和edi自動增加;DF=1,esi和edi自動減少。通常用cld指令來設(shè)置DF標(biāo)志位,使其置為0。

 

4. 舉代碼示例說明。下面使用代碼說明,該代碼的功能是實現(xiàn)strcpy。

定義需要拷貝的源字符變量:

szSource    db 'abcdefghijklmnopqrstuvwxyz', 0

 

4.1 首先看一下不使用lodsb和stosb的方法_StrCopy_1。

_StrCopy_1 proc

    local   @szBuffer[32]:byte

    ;字符串單個復(fù)制指令

    invoke lstrlen, offset szSource

    mov ecx,    eax                     ;要復(fù)制的字節(jié)個數(shù)

   mov esi,    offset szSource        ;源數(shù)據(jù)地址

    lea edi,    @szBuffer               ;目的數(shù)據(jù)地址

@@:

    mov bl, [esi]              ;一次復(fù)制一個字節(jié)

    mov [edi], bl              ;又將該字節(jié)復(fù)制到目的地

 

    inc edi                    ;目的地址和源數(shù)據(jù)地址都向上加一

    inc esi                   

    dec ecx                    ;復(fù)制個數(shù)減一

    ;cmp byte ptr [esi], 0       ;null結(jié)尾的字符串

  cmp dec, 0

    jnz @B                     ;如果沒有復(fù)制到結(jié)尾則繼續(xù)復(fù)制

    mov [edi], 0               ;將目的數(shù)據(jù)的最后一個字節(jié)置為null

   。。。。。                 ;其它代碼

_StrCopy_1 endp

該段代碼,沒有使用任何特殊的指令。esiedi也沒有任何其它的意義只是為了便于理解。用eax,edx代替esi,edi也是一樣的。

 

4.2 使用lodsb和stosb的函數(shù)_StrCopy_2

_StrCopy_2 proc

    local   @szBuffer[32]:byte

   

    xor eax,    eax

    mov esi,    offset szSource    ;將要拷貝的源數(shù)據(jù)地址放入esi中

   test    esi,    esi             ;是否是有效地址?

    jz proc_end                   ;不是的話就停止運行

   

    lea edi,    @szBuffer           ;將要寫入的目的地址放入edi

    test    edi,    edi

    jz proc_end

 

    ;方向標(biāo)志位。當(dāng)方向標(biāo)志位DF=0,esi自動增加;DF=1,esi自動減小

    cld                ;設(shè)置DF=0

 

@@:

    ;代碼的關(guān)鍵所在

   ;一次復(fù)制一個字節(jié),將源地址的一個字節(jié)復(fù)制到al中。

    lodsb                           ;byte ptr [esi]-->al

    ;本次傳輸一個字節(jié),al中的字節(jié)復(fù)制到目的地址中。

    stosb                           ;al-->byte ptr [edi]

   test    al, al ;字符串是否已經(jīng)到了結(jié)尾

    jnz @B      ;沒有到結(jié)尾,繼續(xù)傳輸下一個字符

    ;可以看到:從@@到此處的代碼,就實現(xiàn)了字符串的自動復(fù)制。

;用到了DF標(biāo)志位,esi和edi自動遞增。

;test al, al/jnz @B來判斷是否到了結(jié)尾。也可以將要復(fù)制的長度放到ecx中,

;用代碼dec ecx/test ecx, ecx/jnz @B來實現(xiàn)同樣的功能。

;本函數(shù)比上個函數(shù)多使用了esi和edi寄存器。而且在循環(huán)里面,沒有用指令遞增地址(inc edi/inc esi),而是自動遞增。

 

   ;加上這段代碼,可以求得字符串的長度strlen,并放在ecx里面

    lea ecx,    @szBuffer

    sub edi,    ecx ;地址末尾減去地址頭,等于該段地址的長度(字節(jié)數(shù))

    mov ecx,    edi

    ;除了lodsb外,還有l(wèi)odsw, lodsd,分別是一次傳輸一個字,雙字到ax,eax里面。

    。。。。。。。。。 ;其它代碼

_StrCopy_2 endp

 


 

二、字,雙字操作指令

不是每次都要復(fù)制一個字節(jié),有時候需要復(fù)制一個字或者雙字怎么辦呢?在_StrCopy_2的注釋里面,也提到了,用lodsw/lodsd,相對應(yīng)的指令是stosw/stosd。

概括說來:

 

2.1 從內(nèi)存復(fù)制數(shù)據(jù)到寄存器

【lodsb指令】:從esi指向的源地址中逐一讀取一個字符,送入AL中(然后,可以先判斷這個字符是什么字符,如0dh,0ah之類等,再執(zhí)行相應(yīng)的操作)。

類似有【lodsw指令】:如果是lodsw,表明要處理的是字,而不是字符。則采用的相應(yīng)指令是:lodsw;那么復(fù)制到的寄存器是AX,而不是AL了。

【lodsd指令】:如果是lodsd,表明要處理的是雙字。則采用的相應(yīng)指令是:lodsd;那么復(fù)制到的寄存器是EAX,而不是AL或AX了。

 

2.2 從寄存器復(fù)制數(shù)據(jù)到內(nèi)存

【stosb指令】:將AL中的字符寫入edi指向的目的地址。

類似有【stosw指令】:如果是stosw,表明要處理的是字,而不是字符。則采用的相應(yīng)指令是:stosw;那么被復(fù)制的數(shù)據(jù)源寄存器是AX,而不是AL了。

【stosd指令】:如果是stosd,表明要處理的是雙字。則采用的相應(yīng)指令是:stosd;那么被復(fù)制的數(shù)據(jù)源寄存器是EAX,而不是AL或AX了。

 


 

三、結(jié)合rep指令

上面的介紹,都是一次復(fù)制一個字節(jié)、字或雙字。比如一個雙字?jǐn)?shù)組長度位500個,那么就需要重復(fù)500次使用雙字復(fù)制指令。有沒有方法可以自動復(fù)制完所有數(shù)據(jù)?有,將要復(fù)制的長度500放到ecx中,然后在復(fù)制指令前加上rep指令即可(rep指令表示repeat)。

比如要在一個字?jǐn)?shù)組的內(nèi)存區(qū)域填充0xCC的代碼如下:

    local   @wBuf[256]:word

 

   mov ax, 0cccch                    ;源數(shù)據(jù)

    lea edi,    @wBuf                 ;目的地址

  cld                 ;設(shè)置方向遞增順序

    mov ecx,    256                   ;將要復(fù)制的次數(shù)放在ecx中

    rep stosw                         ;復(fù)制

需要注意的是,如果是復(fù)制字符串的情況,要注意在后面加上0x00. 

 


四  如果要寫一個memcpy函數(shù),使用rep是不行的,因為rep只會將eax里面的東西搬運的到edi,而不會將源字符里面的東西搬運到eax。還是要使用_StrCopy_2里面的方法。

我所寫的一個memcpy函數(shù)如下:

 

 1 ;內(nèi)存拷貝函數(shù) 2 ;_lpDest目的內(nèi)存地址。本函數(shù)將把源內(nèi)存的內(nèi)容搬運到該內(nèi)存地址上,搬運長度是_dwSize 3 ;_lpSource源內(nèi)存地址 4 ;_dwSize,拷貝的長度。即使_lpSource里面包含了0x00的字符,只要小于_dwSize,仍然繼續(xù)搬運。 5 ;例如: 6 ;_lpSource上的內(nèi)容是:abcd(0x00)efg 7 ;_dwSize是8 8 ;函數(shù)運行的結(jié)果是:abcd(0x00)efg,雖然里面有字符串的結(jié)束符,但仍然搬運后面的剩下3個字符 9 _memcpy    proc    _lpDest,    _lpSource,     _dwSize10     mov    edi,    _lpDest11     mov    esi,    _lpSource12     mov    ecx,    _dwSize13     xor    eax,    eax14     cld15 @@:16     lodsb    ;    byte ptr [esi]-->al17     stosb    ;    al -----> byte ptr [edi]18     dec    ecx19     test    ecx,    ecx20     jnz    @B21 22     ret23 _memcpy    endp

 

 可以使用以下代碼作為測試:

 1 local @szBuffer[256]:byte 2  3 invoke  RtlZeroMemory, addr @szBuffer, 256 4 push    'abcd' 5 mov     ebx, esp   ;設(shè)置一個臨時變量 6  7 invoke  _memcpy, addr @szBuffer, ebx, 4 8  9 pop     ebx   ;平衡棧10 invoke  MessageBox, NULL, addr @szBuff, NULL, MB_OK

 


repe   cmpsb   

 repe是一個串操作前綴,它重復(fù)串操作指令,每重復(fù)一次ECX的值就減一
一直到CX為0或ZF為0時停止。

cmpsb是字符串比較指令,把ESI指向的數(shù)據(jù)與EDI指向的數(shù)一個一個的進(jìn)行比較。

當(dāng)repe   cmpsb配合使用時就是字符串比較啦,當(dāng)相同時繼續(xù)比較,不同時不比較


mov   edi,[ebp+08]       將你輸入的密碼的地址付給EDI
mov   esi,[ebp+0c]       真正的地址付給ESI
mov   ecx,[ebp+10]       將他們的長度附給ECX
repe   cmpsb                   進(jìn)行比較
jecxz   00401260           如果CX等于0,即密碼正確跳
mov   eax,00                   密碼不正確時,會EAX為0


再補(bǔ)充一下吧:
    cmpsb是將ESI指向的字節(jié)與EDI指向的字節(jié)進(jìn)行減操作
    如果兩個字符相等,即ZF為1,當(dāng)不相等時ZF為0


    而REPE停止重復(fù)的條件是ZF為0或CX為0,說明啦,當(dāng)ZF為0時
肯定就是字串不同啦,當(dāng)CX為0時,表明字符串比對成功沒有出現(xiàn)
不相等的情況。

  不過我覺得這樣比不太好,如果你的密碼打了8位
  而真正的密碼4位,如果ECX是4的話,他真會比對4位,正好你前4位
  打?qū)?,那輸入的密碼也是正確的啦。如果他的ECX取得是你輸入的密碼
  的個數(shù),就沒問題啦。不知道具體程序是什么樣的,亂評一下,別介意。

 


 

MOVZX

匯編語言數(shù)據(jù)傳送指令MOV的變體。無符號擴(kuò)展,并傳送。
  

movzx一般用于將較小值拷貝到較大值中。 這個指令是非常有用的,大家以后學(xué)程序設(shè)計的話,如果需要處理windows中的消息,例如WM_COMMAND消息,這個消息結(jié)構(gòu)的wParam的高 16位是通知碼,而低16位則是命令id。有時候需要判斷命令id的話,則需要將這個wparam的低16位擴(kuò)展成32位的,并且其余位用0填充。這就用 到了movzx。

movzx是將源操作數(shù)的內(nèi)容拷貝到目的操作數(shù),并將該值0擴(kuò)展至16位或者32位。但是它只適用于無符號整數(shù)。 他大致下面的三種格式。
  movzx 32位通用寄存器, 8位通用寄存器/內(nèi)存單元   
  movzx 32位通用寄存器, 16位通用寄存器/內(nèi)存單元   
  movzx 16位通用寄存器, 8位通用寄存器/內(nèi)存單元   

舉個例子。
  例如   令eax=00304000h   若執(zhí)行 movzx eax, ax后 eax = 00004000h 。   
  若執(zhí)行 movzx eax, ah后 eax = 00000040h。   
  //windows內(nèi)存00304000h存放在內(nèi)存為   //00 40 30 00(這里請參見大端小端存儲方式)所以ax = 4000h ah = 40h   //請注意不要搞混了   

又如:   MOV BL,80H   MOVZX AX,BL   
  運行完以上匯編語句之后,AX的值為0080H。由于BL為80H,最高位也即符號位為1,但在進(jìn)行無符號擴(kuò)展時,其擴(kuò)展的高8位均為0,故賦值A(chǔ)X為0080H。   

 

總結(jié):   movzx其實就是將我們的源操作數(shù)取出來,然后置于目的操作數(shù),目的操作數(shù)其余位用0填充。

 


repne scasb 詳解

SCAS是在檢索目標(biāo)字符串;REPNE/REPNZ是重復(fù)前綴(CX<>0 且ZF=0重復(fù)執(zhí)行字符串指令),類似的還有REPE/REPZ、REP

  1. ax/al   搜索數(shù)據(jù)    
  2. es:di   目標(biāo)串    
  3. cx         串長度    
  4. df         方向標(biāo)志  


利用 REPNE SCAS來檢測代碼中是否被下int3斷點(CC):

  1. 00401241  /$  8D3D 00104000 LEA EDI,DWORD PTR DS:[<ModuleEntryPoint>>;  入口地址401000裝入EDI  
  2. 00401247  |.  B9 97020000   MOV ECX,297                              ;  ECX賦值297  
  3. 0040124C  |.  E8 45000000   CALL 00401296                            ;  CC裝入AL  
  4. 00401251  |.  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]             ;  重復(fù)操作  
  5. 比如斷點設(shè)在00401147處,入口出處為00401000,則F8后,ECX=297-(00401147-00401000+1)=14F,當(dāng)然你也可以在原地不停的按住F4,直到ECX=1后再按F8  
  6. 00401253  |.  85C9          TEST ECX,ECX                             ;  ECX是否為0,如果下了斷點,這里的ECX是非0值  
  7. 00401255  |.  75 3E         JNZ 00401295                             ;  既然你下了斷點,這里一定不能跳  


利用 REPNE SCAS來計算字符串長度:

  1. mov ecx, FFFFFFFF    設(shè)置循環(huán)次數(shù)-1  
  2. sub eax, eax             設(shè)置搜索內(nèi)容0  
  3. repnz                           
  4. scasb                         一直重復(fù)搜索到EDI字符串末尾的0  
  5. not ecx                       得到搜索次數(shù),也就是字符串的完整長度  
  6. dec ecx                       -1得到字符串不包含末尾0的長度  

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
80386ASM程序設(shè)計基礎(chǔ)(三)
函數(shù)是如何被調(diào)用的?
常量、指針和變量的實現(xiàn)機(jī)制
[原創(chuàng)]進(jìn)程和線程
從匯編源碼逐步分析函數(shù)調(diào)用過程
詳談 HOOK API 的技術(shù)
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服