㈠ 求匯編指令解釋dec edx
add byte ptr ds:[eax],al ;將AL寄存器中的內容存入段寄存器DS定位的,由EAX寄存器指向的內存單元.
push edi ;將EDI寄存器壓入堆棧,注意是四個位元組
push ds ;將DS寄存器壓入堆棧,注意是兩個位元組
dec edx ;讓EDX寄存器自減一,即 EDX <- (EDX)-1
㈡ 反匯編小白求知:push esi push edi push 9 push r10 pop edi 然後。。。。。會怎樣
push esi //esi進棧
push edi //edi進棧
push 9 //9進棧
push 10 //10進棧
pop edi //10出棧保存到edi中
//棧中的數據變成了
9
edi
esi
----------沒啥意思的。沒事到0x30網路貼吧耍耍, 一起討論分享交流編程技術。
㈢ 匯編語言函數調用的疑惑
;這段代碼的作用是對局部變數的支持
00401020 55 push ebp ;保存堆棧指針
00401021 8B EC mov ebp,esp ;把esp的值賦給ebp
00401023 83 EC 40 sub esp,40h ;為局部變數留出空間
;保存重要的寄存器
00401026 53 push ebx
00401027 56 push esi
00401028 57 push edi
;處理代碼
00401029 8D 7D C0 lea edi,[ebp-40h]
0040102C B9 10 00 00 00 mov ecx,10h
00401031 B8 CC CC CC CC mov eax,0CCCCCCCCh
00401036 F3 AB rep stos dword ptr [edi]
函數中「}」所對應的代碼如下:
;恢復關鍵的寄存器
00401047 5F pop edi
00401048 5E pop esi
00401049 5B pop ebx
;平衡堆棧
0040104A 8B E5 mov esp,ebp
0040104C 5D pop ebp
;返回
0040104D C3 ret
;你是說堆棧的情況嗎?
;應該是:(棧頂在上面,在所有壓棧操作後)
;EDI 堆棧頂
;ESI
;EBX
;局部變數區(40H大小)
;EBP
;CALL壓入的返回地址
;如果有參數就應該在這里
;出棧操作你自己就就知道啦,後面的指令怎麼樣恢復ESP和平衡堆棧的!
㈣ 求一段匯編的解釋
push eax ;入棧
push edi ;入棧
push ecx ;入棧,這里的三句是為了保護寄存器的數據
mov al, byte ptr[esp + 0x8 + 0xC] ;取一個位元組的數據到AL
mov edi, dword ptr[esp + 0x4 + 0xC] ;取一個BUFFER的地址
mov ecx, dword ptr[esp + 0xC + 0xC] ;取這個BUFFER的大小
rep stosb ;循環給BUFFER賦值,將AL賦給整個BUFFER,循環次數為BUFFER大小.
pop ecx ;出棧
pop edi ;出棧
pop eax ;出棧,這里三句是為了恢復寄存器的數據
ret 0xC ;ret是從子程序返回,後面的值是要平衡棧,即ESP+0XC
--------------------------------------------------------------------------------
你這段代碼既然是C裡面嵌的,我猜想你外部的C代碼大概結構如下
//我猜想C方法結構大概如下,實現的功能就是將BUFFER內存塊全部實始化成指定的CHAR
void memsetChar(char *buffer,char c,int bufLen)
{
__asm{
這里是你求解釋的匯編語言
}
}
下面再給個調用的例子:
char buffer[1024];
memsetChar(buffer,'A',1024); //將數組全部初始化成字元A
最後補充一句,那段匯編的功能等同於C函數 memset函數
㈤ 這道匯編程序 所要表達的意思 。
;這道匯編程序所要表達的意思是: 輸入10個學生成績(用空格隔開),分別統計及格(大於或等於60分)
;和不及格(小於60分)的人數,並按PASS: 和NO PASS: 格式顯示。
;請逐條標明意思 特別是程序中的diplay子程序 一定要每條都寫個大概意思
;
;
;
;用MASM5.0編譯通過,以下是運行結果
;
;E:\masm1>PASS
;323 3 2 3 34 34 7 66 77 77
;PASS:4NO PASS:6
;E:\masm1>PASS
;100 99 99 99 99 99 99 98 97 87
;PASS:10NO PASS:0
;
DATA SEGMENT
ARRAY DW 10 DUP(0) ;定義10個成績存放位置
A1 DB 0 ;及格人數
A2 DB 0 ;不及格人數
C1 DB 'PASS:$' ;顯示及格信息
C2 DB 'NO PASS:$' ;顯示不及格信息
;為了有更好的顯示效果,上一行最好改成: C2 DB 0dh,0ah, 'NO PASS:$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
MOV CX,10 ;輸入10個成績循環數
MOV BL,10
MOV SI,0
BEGIN: MOV DX,0 ;循環入口
Q1: MOV AH,1
INT 21H ;輸入1位數
CMP AL,' ' ;是空格嗎?
JZ Q2
PUSH AX ;不是空格,表示該數還未輸完
MOV AX,DX
MUL BL ;將前面[已輸入部分]*10 =>AX
MOV DX,AX
POP AX
SUB AL,30H
MOV AH,0
ADD DX,AX ;再加上現在輸入的值
JMP Q1
Q2: MOV ARRAY[SI],DX ;是空格,保存該數
ADD SI,2 ;存數指針加2
LOOP BEGIN ;循環
MOV DL,0DH ;此以下6指令輸出回車換行
MOV AH,2
INT 21H
MOV DL,0AH
MOV AH,2
INT 21H
LEA SI,ARRAY ;指向取成績的首個數據
MOV CX,0AH ;取數循環次數
D1: MOV AX,[SI] ;循環入口(取成績)
MOV BX,60
CMP AX,BX ;與60比較
JB S1 ;小於60轉S1
INC A1 ;大於或等於60,計數器A1加1
JMP NEXT5
S1: INC A2 ;小於60,計數器A2加1
NEXT5: INC SI ;移動取成績指針,因為是字,需+2
INC SI
LOOP D1 ;循環
NEXT6: LEA DX,C1 ;顯示PASS:
MOV AH,9
INT 21H
MOV AL,A1
CALL DISPLAY ;調用顯示子程序,顯示A1中(及格人數)的數字
NEXT7: LEA DX,C2 ;顯示NO PASS:
MOV AH,9
INT 21H
MOV AL,A2
CALL DISPLAY ;調用顯示子程序,顯示A2中(不及格人數)的數字
MOV AH,4CH ;程序結束
INT 21H
RET
;=====================
DISPLAY PROC NEAR ;顯示子程序: 將AL中的值轉換為ASCII碼,並顯示
CMP AL,10 ;因為總共只有10個成績,所以最大值為10
JE BE10 ;等於10轉BE10
MOV DL,AL ;<10
ADD DL,30H ;+30H轉換成ASCII碼
MOV AH,2
INT 21H ;顯示
RET ;返回
BE10: ;是10
MOV AH,2
MOV DL,'1' ;顯示'1'
INT 21H
MOV DL,'0'
INT 21H ;顯示'0'
RET ;返回
DISPLAY ENDP
;========================
CODE ENDS
END START
㈥ 函數調用堆棧原理 push ebx push esi push edi是什麼作用
[cpp] view plain
int goo(int a, int b)
{
return a + b;
}
void foo()
{
int a[] = {1, 2, 3};
int result = goo(a[1], a[2]);
printf("result: %d", result);
}
VS2010下編譯
foo函數部分匯編:
[cpp] view plain
00EB3890 push ebp
00EB3891 mov ebp,esp
00EB3893 sub esp,0E4h
00EB3899 push ebx
00EB389A push esi
00EB389B push edi
00EB389C lea edi,[ebp-0E4h]
00EB38A2 mov ecx,39h
00EB38A7 mov eax,0CCCCCCCCh
00EB38AC rep stos dword ptr es:[edi]
00EB38AE mov eax,dword ptr [___security_cookie (0EB7000h)]
00EB38B3 xor eax,ebp
00EB38B5 mov dword ptr [ebp-4],eax
int a[] = {1, 2, 3};
00EB38B8 mov dword ptr [ebp-14h],1
00EB38BF mov dword ptr [ebp-10h],2
00EB38C6 mov dword ptr [ebp-0Ch],3
int result = goo(a[1], a[2]);
00EB38CD mov eax,dword ptr [ebp-0Ch]
00EB38D0 push eax
00EB38D1 mov ecx,dword ptr [ebp-10h]
00EB38D4 push ecx
00EB38D5 call goo (0EB11E5h)
00EB38DA add esp,8
goo函數完整匯編:
[cpp] view plain
00EB1580 push ebp
00EB1581 mov ebp,esp
00EB1583 sub esp,0C0h
00EB1589 push ebx
00EB158A push esi
00EB158B push edi
00EB158C lea edi,[ebp-0C0h]
00EB1592 mov ecx,30h
00EB1597 mov eax,0CCCCCCCCh
00EB159C rep stos dword ptr es:[edi]
return a + b;
00EB159E mov eax,dword ptr [a]
00EB15A1 add eax,dword ptr [b]
}
00EB15A4 pop edi
00EB15A5 pop esi
00EB15A6 pop ebx
00EB15A7 mov esp,ebp
00EB15A9 pop ebp
00EB15AA ret
foo函數push ebp, mov ebp, esp後
保存原ebp,設定新的ebp為當前esp位置
sub esp, 0E4h
給局部變數分配足夠大的棧空間
保存原先的一些寄存器值,每次push,esp繼續向下移
為局部變數a數組賦值
調用goo前Push兩個參數,esp繼續下移
call goo函數時,cpu自動push下一條指令地址,esp繼續下移
在goo函數中,同樣保存foo函數中的ebp值,設定新的ebp,esp等
在執行玩goo函數最後幾句指令時,edi, esi, ebx恢復,esp同時也編程goo中ebp的位置,ebp恢復至foo函數原來的位置(pop ebp)
下一條指令也裝入IP(ret指令),esp繼續向上一步
foo函數中的add esp, 8將esp值繼續往上(清除函數參數)
清除函數參數的工作也可通過ret X在goo函數返回時設定(這樣的話不必在每次調用點上加上add esp, X指令縮短了編譯出來的文件大小,但在子函數中清除將不能做到printf等的可變參數個數功能,因為子函數不知道具體有多少要參數進入了,只有調用處才知道)
㈦ 一個簡單的問題 c語言調用匯編代碼再調用Messagebox函數,求代碼分析
內嵌匯編可以直call函數名調用函數,根本不用這么折騰。另外其實他獲得函數入口的的方法是錯的,知識碰巧能用而已。
lea edx, [ebp - 04h] 就相當於edx = ebp - 04h匯編寫就是
mov edx, ebp
sub edx, 04h
但是前一種寫法方便,執行效率也高。
三個push是把MessageBox的參數推進棧。類似於C里寫MessageBox(edi, edx, edx, edi)(因為前面還有一個push edi)。因為edi是0,edx是那個Hi,所以其實就是MessageBox(0, "Hi!", "Hi!", 0)。
㈧ 使數據段、附加段與代碼段同段的作用是什麼呀
程序不好破解,還有程序中的數據保密性較強。。。一般病毒、黑客和加密程序才這么做吧。。。常規程序好像沒有這么寫的。。。
而且這種做法只能用匯編來完成,其他高級語言都會分段。
給你舉個例子。。。
在C語言中:
char *p = "123";
printf(p);
這兩行代碼經過編譯後,"123"這個數據就會被放置於數據段中,而printf(p)則存在於代碼段。程序執行後會在控制台輸出"123"。
char p[10];
strcpy(p, "123");
printf(p);
這三行代碼經過編譯後,p[10]會在內存中開辟空間並將地址放置於數據段中,"123"也將存在於數據段中,strcpy和printf將存在於代碼段中。程序執行後會在控制台輸出"123"。
在匯編語言中:
.....
mov edi, $ ;這行代碼的意思就是將EIP寄存器的內容寫入EDI,$代表當前指令的EIP
nop
nop
nop
nop
mov ptr byte [edi], '1'
mov ptr byte [edi+1], '2'
mov ptr byte [edi+3], '3'
mov ptr byte [edi+4], 0
push edi
call ....
...
這幾行匯編中存在常量"123",程序運行後在控制台輸出"123",但是卻沒有數據段。當程序執行完一大堆的nop之後,接下去的指令將常量"123"動態的寫入從"mov edi, $"指令開始的3個位元組的空間,並將原指令替換掉了,所以其常量存在於代碼段。
.....
mov edi, $
nop
nop
nop
nop
...
...
push edi
call ....
...
這幾行匯編代碼中,當程序執行到push edi之前的指令時,相當於在代碼段中開辟了N個位元組的空間(N = 多少個nop + "mov edi, $「的長度),通過向[edi]中寫入數據,即相當於strcpy。而這N個位元組的數據儲存空間也存在於代碼段。
由上面的不難看出,如果數據段要和代碼段合並,則必須通過指令動態的在代碼段中分配相應的儲存空間,分配後寫入數據,便會將源指令替換掉。換句話說,這種代碼只能執行一次,若第二次執行,操作系統就會發出CPU遇到無效指令的錯誤。
當然,你也可以把空間分配到永遠不可能執行到的指令處,比如:
...
jmp xxxx
_MemoryStart:
mov edi, $
jmp _EntryContinue
nop
nop
nop
...
nop
_MemoryEnd:
...
這樣一來,你只需要在程序啟動時,使用指令jmp _MemoryStart來分配空間,當程序返回到_EntryContinue的時候把edi的內容保存一下,那麼你就可以永久使用[edi]中的空間了。因為在_MemoryStart之前有一個無條件跳轉,所以無論在什麼情況下代碼執行到此處都會自動跳轉到xxxx處,除非是用jmp指令直接跳轉到_MemoryStart。。。。但是這樣你要完全正確的搞定xxxx所指的地址。而且這個程序沒有任何的兼容性可言,在WinXP SP1下能正常工作,但在SP2、SP3、Vista、Win7下就有可能無法工作了。