最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言逆向分析語法超詳細(xì)分析

 更新時間:2022年11月29日 10:45:13   作者:ch132  
這篇文章主要介紹了C語言逆向分析語法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧

基本數(shù)據(jù)類型

在c中基本數(shù)據(jù)類型分為:char,short,int,long,float,double

以上數(shù)據(jù)類型除float和double外均可以分為有符號(singed)和無符號(unsigned)兩類

有符號時最高位為符號位,用來表示數(shù)據(jù)的正負(fù)

無符號情況下最高位為正常的數(shù)據(jù)位不做特殊含義

類型占位
Char1
short2
int4
long8
float4
Double8

浮點數(shù)類型的存儲

浮點數(shù)類型是比較特殊的,首先他是交給專門的cpu來處理的,比如在80386中就引入了8087協(xié)處理器來專門處理浮點數(shù)的計算

C中的浮點數(shù)存儲方式采用了浮點實數(shù)存儲方式,也就是在全部二進(jìn)制位上選取一段用來表示實數(shù)另一段表示小數(shù)點的位置,如952.7可以分為9527和0.1

C的浮點數(shù)的編碼采用的是ieee標(biāo)準(zhǔn)編碼格式,

如float類型下將浮點數(shù)分為三部分:符號位(1bit)、小數(shù)位(8bit)、實數(shù)位(23bit)

double:符號位(1bit)、小數(shù)位(11bit)、實數(shù)位(52bit)

舉例:12.25f拆分:符號位:0

? 小數(shù)位:1000 0010

? 實數(shù)位:10001 后續(xù)均為0

字符類型的存儲

字符類型是根據(jù)字符的編碼格式將對應(yīng)字符的數(shù)字表示存儲為二進(jìn)制。

具體的字符編碼解析可以劃到底部

指針和引用類型

在C中用指針類型(TYPE*)來表示一個用來存儲一個地址的DWORD類型,用&符號來表示取一個變量的地址

如:int* a;此時a則會被認(rèn)為是一個指針類型,在對a進(jìn)行操作時則會被編譯器編譯為匯編中的間接操作

舉例:

int tmp = 10;
int* a = &tmp;
(*a)+=1;
對應(yīng)的匯編簡單來寫如下:
mov dword ptr [esp],0Ah;           將10存在棧中
lea eax,[esp]						取得tmp所在的地址
mov dword ptr [esp-4],eax					將tmp所在的地址存儲到棧中
mov ecx,dword ptr [esp-4]					取出tmp所在的地址
mov ecx,dword ptr [eax]
add dword ptr ecx,1								將tmp所在地址所指向的內(nèi)容加一
mov dword ptr[eax],ecx

在c中以引用類型(type&)來表示一個操作的集合,每次對這個引用類型的操作都是取變量的內(nèi)容將內(nèi)容作為地址修改此地址中的數(shù)據(jù)并寫回的一個操作的集合

舉例:

int tmp = 10;
int& a = &tmp;
a+=1;
對應(yīng)的匯編簡單來寫如下:
mov dword ptr [esp],0Ah;           將10存在棧中
lea eax,[esp]						取得tmp所在的地址
mov dword ptr [esp-4],eax					將tmp所在的地址存儲到棧中
mov ecx,dword ptr [esp-4]					取出tmp所在的地址
mov ecx,dword ptr [eax]
add dword ptr ecx,1								將tmp所在地址所指向的內(nèi)容加一
mov dword ptr[eax],ecx

可以看到引用類型和指針類型操作編譯為匯編其實是基本一樣的,區(qū)別就在于指針類型變量所存儲的地址也可以進(jìn)行算術(shù)運算

舉例:

int tmp = 10;
int* a = &tmp;
a++;
對應(yīng)的匯編簡單來寫如下:
mov dword ptr [esp],0Ah;           將10存在棧中
lea eax,[esp]						取得tmp所在的地址
mov dword ptr [esp-4],eax					將tmp所在的地址存儲到棧中
mov eax,dword ptr [esp-4]		
add eax,4												此時加的不在是1而是當(dāng)前指針?biāo)硎绢愋偷拇笮?
mov dowrd ptr [esp-4],eax

常量數(shù)據(jù)類型

常量類型表示在程序運行前便已久可以確認(rèn)的數(shù)據(jù),一般存儲在只讀數(shù)據(jù)區(qū),這塊內(nèi)存在頁的屬性上便是不可寫只可讀,所以對這段內(nèi)存的寫操作都會拋出內(nèi)存訪問異常。

常量舉例:如define所定義的常量,或者char* str = “ABC”;這種方式所定義的字符串。

注意const修飾符所修飾的變量并不意味著是在內(nèi)存層面上的常量,他僅僅是編譯器會在編譯過程中進(jìn)行檢測,在程序運行中完全可以通過取地址并修改的間接修改方式對其內(nèi)存數(shù)據(jù)進(jìn)行修改。

函數(shù)

在內(nèi)存的識圖中并沒有函數(shù)這一個說法只存在段的層級每個段都有自己的內(nèi)存屬性可讀可寫可執(zhí)行等待,函數(shù)的目的便是能夠?qū)⒛骋欢蝺?nèi)存明確的用一種概念來分開,而不至于將全部的代碼片段都混雜在一段內(nèi)存中而沒有明確的一個分界和定義。

函數(shù)簡單的來看便是將一塊代碼封裝到一起。下面直接反匯編一個函數(shù)的調(diào)用看一下

首先要說明的是ebp代表了棧底指針,esp代表了棧頂指針

c代碼

int test(int a,int b){
	return a+b;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int a=10,b=1;
	int res = test(a,b);
	printf("%d",res);
	return 0;
}
簡單匯編代碼:
int test(int a,int b){
009D1A50  push        ebp  								//同樣是保存和初始化堆棧
009D1A51  mov         ebp,esp 
009D1A53  sub         esp,0C0h 
009D1A59  push        ebx  
009D1A5A  push        esi  
009D1A5B  push        edi  
009D1A5C  lea         edi,[ebp-0C0h] 			
009D1A62  mov         ecx,30h 
009D1A67  mov         eax,0CCCCCCCCh 
009D1A6C  rep stos    dword ptr es:[edi] 
	return a+b;
009D1A6E  mov         eax,dword ptr [a] 		//取出將a,b做合
009D1A71  add         eax,dword ptr [b] 		//此處的a是ebp+4h,b是ebp+8h
}
009D1A74  pop         edi  
009D1A75  pop         esi  
009D1A76  pop         ebx  
009D1A77  mov         esp,ebp 
009D1A79  pop         ebp  									//回退堆棧
009D1A7A  ret     													//返回
int _tmain(int argc, _TCHAR* argv[])
{
009D1AF0  push        ebp  								//保存ebp
009D1AF1  mov         ebp,esp 						//將棧底指向當(dāng)前棧頂
009D1AF3  sub         esp,0E4h 						//提升堆棧
009D1AF9  push        ebx  								//保存寄存器
009D1AFA  push        esi  
009D1AFB  push        edi  
009D1AFC  lea         edi,[ebp-0E4h] 			//初始化堆棧內(nèi)容
009D1B02  mov         ecx,39h 
009D1B07  mov         eax,0CCCCCCCCh 
009D1B0C  rep stos    dword ptr es:[edi] 
	int a=10,b=1;														//這里開始進(jìn)入我們在main中寫的代碼
009D1B0E  mov         dword ptr [a],0Ah 	//a其實是ebp-4h,這里將10存入到ebp-4,也就是棧底的第																							一個4字節(jié)內(nèi)存
009D1B15  mov         dword ptr [b],1 		//這里同上b是ebp-8h,將1放入棧底開始的第二個4字節(jié)中
	int res = test(a,b);										//下面要注意,下面壓棧是從esp開始壓棧,前面的通過ebp																					所操作的賦值語句是將內(nèi)容存放到開始提升堆棧所占有的內(nèi)存
009D1B1C  mov         eax,dword ptr [b] 	//這里是取出1到eax
009D1B1F  push        eax  								//將eax壓棧
009D1B20  mov         ecx,dword ptr [a] 	//取出10到ecx
009D1B23  push        ecx  								//ecx壓棧
009D1B24  call        func (9D126Ch) 			//調(diào)用我們的test方法此時可以看做一個																														jmp詳細(xì)的后續(xù)再講
009D1B29  add         esp,8 							//平衡傳入?yún)?shù)時提升的堆棧
009D1B2C  mov         dword ptr [res],eax //eax便是返回值
	printf("%d",res);
009D1B2F  mov         esi,esp 
009D1B31  mov         eax,dword ptr [res] 
009D1B34  push        eax  
009D1B35  push        offset string "%d" (9D774Ch) 
009D1B3A  call        dword ptr [__imp__printf (9DA40Ch)] 
009D1B40  add         esp,8 
009D1B43  cmp         esi,esp 
009D1B45  call        @ILT+435(__RTC_CheckEsp) (9D11B8h) 
	return 0;
009D1B4A  xor         eax,eax 
}

從上面的例子可見函數(shù)的調(diào)用便是從代碼段中的一塊跳轉(zhuǎn)到另一塊去執(zhí)行,在執(zhí)行結(jié)束后再返回,

函數(shù)的參數(shù)是通過棧來傳遞的,在函數(shù)結(jié)束后要重新保證?;赝说秸{(diào)用函數(shù)之前的狀態(tài)。

其次call命令可以分為兩個部分

  • 壓入當(dāng)前地址作為函數(shù)調(diào)用結(jié)束后回退時用
  • jmp到對應(yīng)的位置(如果是跨段調(diào)用則是jmp far)

函數(shù)調(diào)用的約定分為三類

  • stdcall:標(biāo)準(zhǔn)的winapi調(diào)用約定平棧操作交給函數(shù)自行處理,通過ret arg來實現(xiàn)
  • cdecl:c語言調(diào)用約定,平棧操作交給調(diào)用方實現(xiàn),也就是上面例子中的調(diào)用
  • fastcall:參數(shù)通過寄存器傳遞,如eax,ebx

結(jié)構(gòu)體和類

結(jié)構(gòu)體就是將一系列數(shù)據(jù)整合到一起的一塊內(nèi)存,下面通過例子來看一下

struct test_struct{
	int a;
	char b;
	int c;
};
int _tmain(int argc, _TCHAR* argv[])
{
	struct test_struct s;
	s.a = 10;
	s.b = 11;
	s.c = 12;
	test(&s);
	return 0;
}

首先建立了一個結(jié)構(gòu)體有三個參數(shù)

先來看一下結(jié)構(gòu)體在內(nèi)存中的存儲方式

int _tmain(int argc, _TCHAR* argv[])
{
。。。。。。。
	struct test_struct s;
	s.a = 10;
00E524DE  mov         dword ptr [s],0Ah 			//這里的s可以簡單看為ebp-4
	s.b = 11;
00E524E5  mov         byte ptr [ebp-0Ch],0Bh 
	s.c = 12;
00E524E9  mov         dword ptr [ebp-8],0Ch 
	test(&s);
00E524F0  lea         eax,[s] 						//lea為取地址的指令,前面我們也遇到過
00E524F3  push        eax  								//將這個地址作為參數(shù)傳遞
00E524F4  call        test (0E511B8h) 
00E524F9  add         esp,4 
	return 0;
00E524FC  xor         eax,eax 
。。。。。
}

可以看出來結(jié)構(gòu)體在內(nèi)存中的存儲方式便是將數(shù)據(jù)按順序排放在內(nèi)存中并根據(jù)字段類型的大小計算偏移量來取得對應(yīng)的字段內(nèi)容

如果我們直接將struct關(guān)鍵字改為class看看會不會出錯

class test_struct{
public:
	int a;
	char b;
	int c;
};
void test(test_struct* s){
	printf("%d",s->a);
}
int _tmain(int argc, _TCHAR* argv[])
{
	test_struct s;
	s.a = 10;
	s.b = 11;
	s.c = 12;
	test(&s);
	return 0;
}

改后的代碼,完全可以運行

并且如果看返匯編的話會發(fā)現(xiàn)匯編代碼也沒有變化

下面我們將函數(shù)放到class中看一下匯編是否會有變化

class test_struct{
public:
	int a;
	char b;
	int c;
	
	void test(test_struct* s){
	printf("%d",s->a);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
	test_struct s;
	s.a = 10;
	s.b = 11;
	s.c = 12;
	s.test(&s);
	return 0;
}
匯編只看main這部分的代碼
  int _tmain(int argc, _TCHAR* argv[])
{
。。。。。
	test_struct s;
	s.a = 10;
00D3339E  mov         dword ptr [s],0Ah 
	s.b = 11;
00D333A5  mov         byte ptr [ebp-0Ch],0Bh 
	s.c = 12;
00D333A9  mov         dword ptr [ebp-8],0Ch 
	s.test(&s);
00D333B0  lea         eax,[s] 
00D333B3  push        eax  
00D333B4  lea         ecx,[s] 
00D333B7  call        test_struct::test (0D311D6h) 
	return 0;
00D333BC  xor         eax,eax 
  。。。。。。。。
}

注意 lea ecx,[s] 這段代碼,這個ecx便是所謂的this指針,通過編譯器將結(jié)構(gòu)體自己的地址作為參數(shù)傳入函數(shù)這樣就可以通過this符號訪問結(jié)構(gòu)體自己了。其余的部分完全沒有變化,調(diào)用class的函數(shù)時也是通過地址調(diào)用的。

注意:數(shù)據(jù)在內(nèi)存中的存儲還取決于數(shù)據(jù)對齊,這部分的知識在我前面的筆記中有詳細(xì)解析

面向?qū)ο蟮奶匦?/h2>

面向?qū)ο蟮奶匦杂?/p>

  • 封裝
  • 繼承
  • 多態(tài)

封裝在上一塊我們已經(jīng)看過了,便是將操作數(shù)據(jù)的算法和存放數(shù)據(jù)的結(jié)構(gòu)體封裝到一起來調(diào)用,真正的實現(xiàn)通過編譯器來實現(xiàn)。

下面說一下

繼承

結(jié)構(gòu)體

異常處理

字符編碼

計算機(jī)中的存儲是以字節(jié)為單位的,能反映的也僅僅是數(shù)字而已,為了能夠用數(shù)字將文字信息反映出來人們設(shè)計出了各種字符編碼表,將數(shù)字與文字對應(yīng)。

1、ASCI編碼

1.原始Ascii編碼

原始ASCI使用1到127(0X00~0X7F)來對應(yīng)常用的一些字母等文本,127到255則是擴(kuò)展到一些不常用的類似于=號這種內(nèi)容。

但原始ASCI所支持的字符僅僅能夠反映英文國家的使用場景。

2.ASCI擴(kuò)展編碼

對于某些地區(qū)是無法用原始ASCI編碼來反映當(dāng)?shù)氐恼Z言的,所以就有了ASCI擴(kuò)展編碼的這種形式。

擴(kuò)展ASIC編碼將不常用的127到255的(0x80~0xFF)位置采用兩個數(shù)字對應(yīng)一個文字的方式

如:可能128和129代表一個中,129和130代表一個國

呢么中國對應(yīng)的編碼就是:0x 8081 8182

例如國內(nèi)常用的GBK、GB2312和臺灣的big5等編碼方式都是采取的此類

但是這種編碼方式有一個問題,就是他占用了ASCI表的127到255的位置并且不同的地區(qū)這部分的編碼均不一樣,呢么國內(nèi)的中文文件發(fā)到國外采用了不同的編碼去讀取則會出現(xiàn)亂碼

2、Unicode編碼

Unicode編碼就是為了解決ASCii擴(kuò)展碼在不同地區(qū)的實現(xiàn)下解碼后對應(yīng)不同的文字這個問題

Unicode編碼將全世界常用的符合都構(gòu)建到一個表中,這個表的范圍是:0x10 FF FF到0
Unicode僅僅提供了一個表,他并沒有對存儲做過多的要求,而下面所說的utf-8和utf-16以及現(xiàn)在的utf-32則是對Unicode編碼存儲方式的不同實現(xiàn)

1.unicode編碼實現(xiàn)(utf-8)

utf-8較之utf-16在存儲上更為復(fù)雜,但是所占空間是更小的,這也是網(wǎng)絡(luò)傳輸大多為utf-8的格式的原因

存儲規(guī)則:

如果目標(biāo)符合在Unicode中為:0到00007F則會被編碼為:0xxx xxxx

如果目標(biāo)符合在Unicode中為:80到00007FF則會被編碼為:110xx xxx 10xx xxxx

如果目標(biāo)符合在Unicode中為:800到00FFFF則會被編碼為:1110 xxxx 10xx xxxx 10xx xxxx

如果目標(biāo)符合在Unicode中為:10000到10FFFF則會被編碼為:1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx

2.unicode編碼實現(xiàn)(utf-16)

utf-16名如其意,就是以兩個byte為單位進(jìn)行存儲。

舉例:如果說在Unicode編碼中 中對應(yīng)0x10 61 62

那么采用utf-16存儲在文件中的byte就是 0x 0010 6162

到此這篇關(guān)于C語言逆向分析語法超詳細(xì)分析的文章就介紹到這了,更多相關(guān)C語言逆向分析語法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • linux內(nèi)核select/poll,epoll實現(xiàn)與區(qū)別

    linux內(nèi)核select/poll,epoll實現(xiàn)與區(qū)別

    這篇文章主要介紹了linux內(nèi)核select/poll,epoll實現(xiàn)與區(qū)別,需要的朋友可以參考下
    2016-11-11
  • c語言經(jīng)典習(xí)題之逆序字符串詳解

    c語言經(jīng)典習(xí)題之逆序字符串詳解

    這篇文章主要為大家介紹了c語言習(xí)題之逆序字符串,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • C++實現(xiàn)LeetCode(65.驗證數(shù)字)

    C++實現(xiàn)LeetCode(65.驗證數(shù)字)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(65.驗證數(shù)字),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Qt實現(xiàn)串口助手

    Qt實現(xiàn)串口助手

    這篇文章主要為大家詳細(xì)介紹了Qt實現(xiàn)串口助手,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 簡單了解C++語言中的二元運算符和賦值運算符

    簡單了解C++語言中的二元運算符和賦值運算符

    這篇文章主要介紹了C++語言中的二元運算符和賦值運算符,文中列出了可重載的運算符列表,需要的朋友可以參考下
    2016-01-01
  • C++實現(xiàn)LeetCode(23.合并k個有序鏈表)

    C++實現(xiàn)LeetCode(23.合并k個有序鏈表)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(23.合并k個有序鏈表),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言詳解UDP通信的實現(xiàn)

    C語言詳解UDP通信的實現(xiàn)

    UDP協(xié)議是用戶數(shù)據(jù)報協(xié)議,面向無連接的、不穩(wěn)定、不可靠、不安全的數(shù)據(jù)報傳遞---更像是是收發(fā)短信;UDP傳輸不需要建立連接,傳輸效率更高,在穩(wěn)定的局域網(wǎng)內(nèi)環(huán)境相對可靠;UDP天然支持多客戶端
    2022-05-05
  • Opencv實現(xiàn)拼圖板游戲

    Opencv實現(xiàn)拼圖板游戲

    這篇文章主要為大家詳細(xì)介紹了Opencv實現(xiàn)拼圖板小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C語言實現(xiàn)設(shè)備管理系統(tǒng)

    C語言實現(xiàn)設(shè)備管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)設(shè)備管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Qt?關(guān)于容器的遍歷迭代器的使用問題小結(jié)

    Qt?關(guān)于容器的遍歷迭代器的使用問題小結(jié)

    Qt是一個跨平臺的 C++ 開發(fā)庫,主要用來開發(fā)圖形用戶界面程序,當(dāng)然也可以開發(fā)不帶界面的命令行程序,本文重點給大家介紹Qt?關(guān)于容器的遍歷迭代器的使用問題小結(jié),感興趣的朋友一起看看吧
    2022-03-03

最新評論

颍上县| 红桥区| 平武县| 乡宁县| 甘肃省| 绥江县| 温宿县| 潢川县| 灵武市| 哈尔滨市| 石家庄市| 黑龙江省| 浦北县| 桦甸市| 天长市| 冷水江市| 七台河市| 阳新县| 四川省| 定南县| 宜丰县| 卢湾区| 大同市| 古蔺县| 绍兴县| 灵石县| 彩票| 龙江县| 迁西县| 红原县| 余江县| 西和县| 霍邱县| 象州县| 内乡县| 新竹市| 扎赉特旗| 南江县| 柯坪县| 崇文区| 额尔古纳市|