反彙編代碼還原之除數為非2的冪

2021-02-19 看雪學院


本文為看雪論壇精華文章

看雪論壇作者ID:TkBinary



https://bbs.pediy.com/thread-224499.htmhttps://bbs.pediy.com/thread-224500.htm


反彙編代碼還原之優化方式

反彙編代碼還原之除數為2的冪

反彙編代碼還原之加減乘

* 點擊文字即可跳轉文章



1.1 簡介除法在非2的冪優化上,採用的是除法轉變為乘法的形式,在學習這方面知識的時候我們先了解下簡單的數學知識,也有助於我們能看懂公式。
1.2 分數
1.2.1分數加法不同分母想加,如果是不同分母想加你就要進行尋找最小公分母。公分母指的是,當兩個或者以上的分數有相同的分母,那麼他們便是公分母。注意這裡是公分母,而不是最小公分母,最小公分母指的是兩個分數以上,最小的公分母。最小公分母我們可以列出分母的倍數。如果有兩個分數那麼都列出分母的倍數,找出相同的倍數,然後讓其等價即可。我們發現最小公倍數都是6,所以我們的分子分母都*2轉為為相同分母然後進行想加即可。
1.2.1分數乘法

分數乘法

 **分數*分數 是分子 * 分子 分母 * 分母**

如下:

 

口訣: 乘分數,沒難度,上乘上,下乘下,再約分。

整數相乘

如果一個整數 * 一個分數,那麼這個分數就可以看做是分子,而分母就是1。

例子:

至於約分,可以尋找最小公因數,跟公倍數相反。

公倍數是找出相乘,公因數就是找出可以分子/分母的數,都去除同一個數。




2.1 高級代碼與反彙編
int main(int argc, char* argv[]){    /*    除法    */      int NumberOne = 0;      int NumberTwo = 0;


scanf("%d",&NumberOne); scanf("%d",&NumberTwo);

int Count1 = NumberOne / 3;
int Count2 = NumberTwo / 5;
int Count3 = NumberTwo / 6;
int Count4 = NumberTwo / 9;

printf("%d%d%d%d%d",Count4,Count3,Count2,Count1); system("pause");
return 0;}

彙編對應代碼:

.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp).text:00401000 _main           proc near               ; CODE XREF: start+AF↓p.text:00401000.text:00401000 var_8           = dword ptr -8.text:00401000 var_4           = dword ptr -4.text:00401000 argc            = dword ptr  4.text:00401000 argv            = dword ptr  8.text:00401000 envp            = dword ptr  0Ch.text:00401000.text:00401000                 sub     esp, 8.text:00401003                 xor     eax, eax.text:00401005                 mov     [esp+8+var_8], eax.text:00401009                 mov     [esp+8+var_4], eax.text:0040100D                 lea     eax, [esp+8+var_8].text:00401011                 push    eax.text:00401012                 push    offset aD       ; "%d".text:00401017                 call    _scanf.text:0040101C                 lea     ecx, [esp+10h+var_4].text:00401020                 push    ecx.text:00401021                 push    offset aD       ; "%d".text:00401026                 call    _scanf
//第一段.text:0040102B mov ecx, [esp+18h+var_8].text:0040102F mov eax, 55555556h.text:00401034 imul ecx.text:0040103A mov eax, edx.text:0040103C shr eax, 1Fh.text:0040103F add edx, eax
//第二段.text:00401036 mov ecx, [esp+18h+var_4].text:00401041 mov eax, 66666667h.text:00401047 imul ecx.text:00401049 sar edx, 1.text:0040104B mov eax, edx.text:0040104D shr eax, 1Fh.text:00401050 add edx, eax.text:00401057 push edx //這裡原先是流水線優化給提到上邊來了//第三段.text:00401052 mov eax, 2AAAAAABh.text:00401058 imul ecx.text:0040105A mov eax, edx.text:0040105C shr eax, 1Fh.text:0040105F add edx, eax.text:00401066 push edx //同上流水線優化
//第四段.text:00401061 mov eax, 38E38E39h.text:00401067 imul ecx.text:00401069 sar edx, 1.text:0040106B mov ecx, edx.text:0040106D shr ecx, 1Fh.text:00401070 add edx, ecx.text:00401072 push edx

.text:00401073 push offset aDDDDD ; "%d%d%d%d%d".text:00401078 call _printf.text:0040107D push offset aPause ; "pause".text:00401082 call _system.text:00401087 xor eax, eax.text:00401089 add esp, 30h.text:0040108C retn.text:0040108C _main endp

2.2 除法非2的冪還原

乍一看上面彙編代碼,除法怎麼變為了這樣,為什麼又有乘法又有除法,還有調整等,那麼這裡就著重講解一下。

 

如果想要直接還原,那麼我們把代碼定式提取出來,直接進行還原。

代碼定式:

mov     ecx, 被除數mov     eax, M值imul    ecxsar     edx, nmov     eax, edxshr     eax, 1Fhadd     edx, eaxpush    edx

根據彙編我們只需要看三個點即可,並且得出三個點的公式得原理:

其中M是編譯器計算出來了, ecx是被除數,這裡sar n值,直接操作的是edx。這裡其實是除法轉變為了乘法,而如果除法轉變為乘法,那麼在32位年代下,兩個數相乘32的值是不會放下的。所以我們這裡其實使用的是 edx,eax 來代表乘法的結果,然後我們直接操作了乘積的高位,這裡右移1,等價於是除以2^n+1。 

那麼我們還原的時候直接記住死公式就可以,2^32+1/M 。

 

直接統計n的取值,然後用 2的32次方 + n即可。因為乘積的低位時代表2^32次方,這裡直接是對乘積高位做操作,所以我們需要加上低位的32次方的值。

 

例子還原:

.text:0040102B                 mov     ecx, [esp+18h+var_8].text:0040102F                 mov     eax, 55555556h.text:00401034                 imul    ecx.text:0040103A                 mov     eax, edx                //這裡直接使用的是edx.而沒有對edx做修改.所以我們的n值就是0.text:0040103C                 shr     eax, 1Fh.text:0040103F                 add     edx, eax

我們套用公式:

2.99直接向上取整 = 3,所以這裡我們就尋得被除數為3。
2.3 除數為非2的冪的優化與原理
.text:00401061                 mov     eax, 38E38E39h.text:00401067                 imul    ecx.text:00401069                 sar     edx, 1.text:0040106B                 mov     ecx, edx
.text:0040106D shr ecx, 1Fh.text:00401070 add edx, ecx.text:00401072 push edx

這裡我們彙編分為兩部分。上邊是可以直接套用公式還原,而下方其實是獲取符號位,調整一下符號位。shr 邏輯右移最高位以0填充,右移31(1F)位 取得符號位,然後這裡有一個加法。其實這個加法也是套路,跟我們之前講解的無分支優化差不多。如果結果是正數那麼 add edx,eax 就是加0,等於什麼都不幹;如果是結果是負數那麼我們就需要除法的商做調整,做加1調整。如果想要了解為什麼非2的冪代碼會變成上面的代碼,那麼我們就要理解下原理。其中 2n/b這個是可以在編譯期中計算出來的,VC++6.0 或者VS2019 在編譯 期間n的取值是大於32的,所以是可以算出來的。所以我們的公式可以變為如下,在這裡我們把編譯器可以計算出來的值記做C。那麼可以得出以下公式:最終簡化為就是(a * c) >> n,而反過頭來看我們的彙編代碼:
.text:00401061                 mov     eax, 38E38E39h.text:00401067                 imul    ecx.text:00401069                 sar     edx, 1

ecx eax / 2^33 這條公式就正好對應著我們除法轉變為乘法的原理,和我們上面的公式一樣,(a c) >> n。所以我們解方程即可,2^n / b = M值,那麼 2^n / M = b ,b就是我們的要求的除數,所以得出我們的除數。
2.4 總結除法還原公式這裡的C其實就是2^n/b,在彙編中我們也設為M,所以也可以寫為如下:對於上面我們記住代碼定式也可以進行還原,當然熟悉除法轉變為乘法的原理更好。高級代碼看其特徵我們發現其實是一樣的,都可以使用除法轉乘法的公式來進行還原。除法還原公式其實就是解方程了,解開就可以得到被除數。

int main(int argc, char* argv[]){    /*    除法    */     unsigned int NumberOne = 0;     unsigned int NumberTwo = 0;


scanf("%u",&NumberOne); scanf("%u",&NumberTwo);

unsigned int Count1 = NumberOne / 3;
unsigned int Count2 = NumberTwo / 5;
unsigned int Count3 = NumberTwo / 6;
unsigned int Count4 = NumberTwo / 9;

printf("%d%d%d%d%d",Count4,Count3,Count2,Count1); system("pause");
return 0;}

.text:00401005                 mov     [esp+8+var_8], eax.text:00401009                 mov     [esp+8+var_4], eax
.text:0040102B mov eax, 2863311531.text:00401030 mov ecx, [esp+18h+var_4].text:00401034 mul [esp+18h+var_8].text:00401038 shr edx, 1
.text:0040103A mov eax, 3435973837.text:0040103F push edx.text:00401040 mul ecx.text:00401042 shr edx, 2
.text:00401045 mov eax, 0AAAAAAABh.text:0040104A push edx.text:0040104B mul ecx.text:0040104D shr edx, 2
.text:00401050 mov eax, 38E38E39h.text:00401055 push edx.text:00401056 mul ecx.text:00401058 shr edx, 1.text:0040105A push edx


3.1 無符號非2的冪除數為正代碼反彙編還原看如上代碼,根據除法轉為乘法公式 (a * b) >> n,我們可以求出:2^n / b = M 2^n/M = b(除數常量)
.text:0040102B                 mov     eax, 2863311531.text:00401030                 mov     ecx, [esp+18h+var_4].text:00401034                 mul     [esp+18h+var_8].text:00401038                 shr     edx, 1

取N 值 = 1,取M值 = 2863311531(注意這裡IDA我按了下H轉為10進位來查看.這樣方便我們用科學計算器來進行運算)。

被除數 = 2^33除數 = M求除數公式 = 2^n/M = b代入公式2^33 / 2863311531 = 2.999999999 向上取整 = 3 所以得出這裡的除數為3. ecx = var4所以這裡反彙編為高級代碼為 var_4 / 3

3.2 無符號非2的冪除數為負數反彙編代碼還原
int main(int argc, char* argv[]){    /*    除法    */     unsigned int NumberOne = 0;     unsigned int NumberTwo = 0;


scanf("%u",&NumberOne); scanf("%u",&NumberTwo);

unsigned int Count1 = NumberOne / -3;
unsigned int Count2 = NumberTwo / -5;
unsigned int Count3 = NumberTwo / -6;
unsigned int Count4 = NumberTwo / -9;

printf("%d%d%d%d%d",Count4,Count3,Count2,Count1); system("pause");
return 0;}

.text:00401005                 mov     [esp+8+var_8], eax.text:00401009                 mov     [esp+8+var_4], eax
/-3.text:0040102B mov eax, 40000001h.text:00401030 mov ecx, [esp+18h+var_4].text:00401034 mul [esp+18h+var_8].text:00401038 shr edx, 1Eh.text:00401040 push edx
/-5.text:0040103B mov eax, 80000003h.text:00401041 mul ecx.text:00401043 shr edx, 1Fh.text:0040104B push edx
/-6.text:00401046 mov eax, 7.text:0040104C mul ecx.text:0040104E mov eax, ecx.text:00401050 sub eax, edx.text:00401052 shr eax, 1.text:00401054 add eax, edx.text:00401056 shr eax, 1Fh.text:00401059 push eax/-9.text:0040105A mov eax, 80000005h.text:0040105F mul ecx.text:00401061 shr edx, 1Fh.text:00401064 push edx

根據上面反彙編代碼,我們看到三個地方有我們的疑似 (a * c) >> n的代碼,也就是除法轉變為乘法的公式。設 M = 40000001h =10進位的 1073741825以計算器的科學計算計算出的數值是4294967292(10進位)。那麼我們將這個數複製到以程式設計師計算的計算器中(複製到Dec 10進位輸入)可以看到是一個負數。注意輸入的時候以QWORD輸入,然後再點擊一下變成DWORD則可以看到表達為-4。此時直接對其NOT取反則可以得到原始的被除數,但是這個被除數常量是負數。你也可以讓此值做+1調整變為4294967293,那麼就得出了數直接就是-3,可以很明確的知道我們的被除數是-3。
3.3 特殊彙編看到上面有一段代碼,我們特別不理解為什麼/-6彙編變了。2^64 / 4,294,967,302 = 0x100000006,最高位為符號位,代表這是個負數也就是-6。如果根據定式還原得出的結果為0xFFFFFFF9,然後對其取反得到6。
mov regA,[ebp - xxx]mov reg,Mmul regAsub regA,edxshr regA,nadd regA,edxshr regA,(n-1)

這裡取出兩個n值。1+31= 32,所以n值為32。

 

代入公式得:

 

2^64 / 4,294,967,303 = 0XFFFFFFF9

 

關於特殊彙編在下一篇應該會詳細講解。




4.1 為什麼學習除法優化

還是那句話為什麼學習除法優化,好就以我們上面的例子為例,那麼使用IDA F5查看。

請問看到這種代碼你怕了嗎?直接反彙編可以得出這一段代碼我是幹啥,用IDA反彙編就會得出右移等等,在我們看來就是硬彙編。

 

也就是硬著頭皮還原的,所以說這就是我們學習的意義所在。當然F5還是很強大的,但是我們學會了能更好的幫助我們進行反彙編,更好的通過反彙編從而還原為高級代碼。


其實還是老生常談,拿高版本與低版本做個對比,看看優化方式是否發生了改變。

5.1 vs2019 x86 有符號非2的冪優化

高級代碼:

int main(int argc, char* argv[]){    /*    除法    */      int NumberOne = 0;      int NumberTwo = 0;    scanf("%d",&NumberOne);    scanf("%d",&NumberTwo);      int Count1 = NumberOne / 3;     int Count2 = NumberTwo / 5;     int Count3 = NumberTwo / 6;          int Count4 = NumberTwo / 9;    printf("%d%d%d%d%d",Count4,Count3,Count2,Count1);    system("pause");     return 0;}

彙編:

.text:00401080                 push    ebp.text:00401081                 mov     ebp, esp.text:00401083                 sub     esp, 8.text:00401086                 lea     eax, [ebp+var_4].text:00401089                 mov     [ebp+var_4], 0.text:00401090                 push    eax.text:00401091                 push    offset unk_41ECDC.text:00401096                 mov     [ebp+var_8], 0.text:0040109D                 call    sub_401050.text:004010A2                 lea     eax, [ebp+var_8].text:004010A5                 push    eax.text:004010A6                 push    offset unk_41ECDC.text:004010AB                 call    sub_401050 .text:004010B0                 mov     ecx, [ebp+var_8].text:004010B3                 mov     eax, 55555556h.text:004010B8                 imul    [ebp+var_4].text:004010BB                 mov     eax, edx.text:004010BD                 shr     eax, 1Fh.text:004010C0                 add     eax, edx.text:004010C2                 push    eax .text:004010C3                 mov     eax, 66666667h.text:004010C8                 imul    ecx.text:004010CA                 sar     edx, 1.text:004010CC                 mov     eax, edx.text:004010CE                 shr     eax, 1Fh.text:004010D1                 add     eax, edx.text:004010D3                 push    eax .text:004010D4                 mov     eax, 2AAAAAABh.text:004010D9                 imul    ecx.text:004010DB                 mov     eax, edx.text:004010DD                 shr     eax, 1Fh.text:004010E0                 add     eax, edx.text:004010E2                 push    eax .text:004010E3                 mov     eax, 38E38E39h.text:004010E8                 imul    ecx.text:004010EA                 sar     edx, 1.text:004010EC                 mov     eax, edx.text:004010EE                 shr     eax, 1Fh.text:004010F1                 add     eax, edx.text:004010F3                 push    eax.text:004010F4                 push    offset aDDDDD   ; "%d%d%d%d%d".text:004010F9                 call    sub_401020.text:004010FE                 push    offset aPause   ; "pause".text:00401103                 call    sub_4048E7.text:00401108                 add     esp, 28h.text:0040110B                 xor     eax, eax.text:0040110D                 mov     esp, ebp.text:0040110F                 pop     ebp

這裡流水線優化等也不去掉了,可以發現跟VC6.0無任何區別。


5.2 vs2019 x64有符號非2的冪優化

高級代碼:

int main(int argc, char* argv[]){    /*    除法    */    __int64 NumberOne = 0;    __int64 NumberTwo = 0;    scanf("%I64d", &NumberOne);    scanf("%I64d", &NumberTwo);     __int64 Count1 = NumberOne / 3;    __int64 Count2 = NumberTwo / 5;    __int64 Count3 = NumberTwo / 6;    __int64 Count4 = NumberTwo / 9;    printf("%I64d%I64d%lld%lld", Count4, Count3, Count2, Count1);    system("pause");     return 0;}

反彙編:

text:00000001400010D0                 sub     rsp, 38h.text:00000001400010D4                 xor     eax, eax.text:00000001400010D6                 lea     rdx, [rsp+38h+arg_10].text:00000001400010DB                 lea     rcx, aI64d      ; "%I64d".text:00000001400010E2                 mov     [rsp+38h+arg_10], rax.text:00000001400010E7                 mov     [rsp+38h+arg_18], rax.text:00000001400010EC                 call    sub_140001080.text:00000001400010F1                 lea     rdx, [rsp+38h+arg_18].text:00000001400010F6                 lea     rcx, aI64d      ; "%I64d".text:00000001400010FD                 call    sub_140001080.text:0000000140001102                 mov     rcx, [rsp+38h+arg_18] .text:0000000140001107                 mov     rax, 5555555555555556h.text:0000000140001111                 imul    [rsp+38h+arg_10].text:0000000140001116                 mov     rax, 6666666666666667h.text:0000000140001120                 mov     r10, rdx.text:0000000140001123                 shr     r10, 3Fh.text:0000000140001127                 add     r10, rdx.text:000000014000112A                 imul    rcx.text:000000014000112D                 mov     [rsp+38h+var_18], r10.text:0000000140001132                 mov     r9, rdx.text:0000000140001135                 sar     r9, 1.text:0000000140001138                 mov     rax, r9.text:000000014000113B                 shr     rax, 3Fh.text:000000014000113F                 add     r9, rax .text:0000000140001142                 mov     rax, 2AAAAAAAAAAAAAABh.text:000000014000114C                 imul    rcx.text:000000014000114F                 mov     rax, 1C71C71C71C71C72h.text:0000000140001159                 mov     r8, rdx.text:000000014000115C                 shr     r8, 3Fh.text:0000000140001160                 add     r8, rdx.text:0000000140001163                 imul    rcx.text:0000000140001166                 lea     rcx, aI64dI64dLldLld ; "%I64d%I64d%lld%lld".text:000000014000116D                 mov     rax, rdx.text:0000000140001170                 shr     rax, 3Fh.text:0000000140001174                 add     rdx, rax.text:0000000140001177                 call    sub_140001020.text:000000014000117C                 lea     rcx, aPause     ; "pause".text:0000000140001183                 call    sub_1400045C4.text:0000000140001188                 xor     eax, eax.text:000000014000118A                 add     rsp, 38h.text:000000014000118E                 retn

觀看反彙編其實跟x86一致。

 

這裡還是去掉流水線優化,提取核心代碼位置進行反彙編。

M數值變大,還是代入公式即可。這裡使用的mov r10,rdx,說明直接使用的rdx, rdx是一個64位數,所以 2^64 / M = 2.9999999 向上取整 = 3。


5.3 linux gcc x86 有符號非2的冪

高級代碼:

 int main(){     int NumberOne = 0;    int NumberTwo = 0;    scanf("%d", &NumberOne);    scanf("%d", &NumberTwo);    int Count1 = NumberOne / 3;    int Count2 = NumberTwo / 5;    int Count3 = NumberTwo / 6;    int Count4 = NumberTwo / 9;    printf("%d%d%d%d", Count4, Count3, Count2, Count1);    scanf("%d", &Count4);    scanf("%d", &Count3);    scanf("%d", &Count2);    scanf("%d", &Count1);    printf("%d%d%d%d", Count4, Count3, Count2, Count1);    return 0;}

如果你是64位系統,那麼你使用gcc命令如下:

編譯出來即可,其實下面反彙編跟x86 vc++6.0 vs2019 一樣,可以不用看了。

 

反彙編:

.text:080484BB ; int __cdecl main(int argc, const char **argv, const char **envp).text:080484BB                 public main.text:080484BB main            proc near               ; DATA XREF: _start+17↑o.text:080484BB.text:080484BB var_24          = dword ptr -24h.text:080484BB var_20          = dword ptr -20h.text:080484BB var_1C          = dword ptr -1Ch.text:080484BB var_18          = dword ptr -18h.text:080484BB var_14          = dword ptr -14h.text:080484BB var_10          = dword ptr -10h.text:080484BB var_C           = dword ptr -0Ch.text:080484BB argc            = dword ptr  8.text:080484BB argv            = dword ptr  0Ch.text:080484BB envp            = dword ptr  10h.text:080484BB.text:080484BB ; __unwind {.text:080484BB                 lea     ecx, [esp+4].text:080484BF                 and     esp, 0FFFFFFF0h.text:080484C2                 push    dword ptr [ecx-4].text:080484C5                 push    ebp.text:080484C6                 mov     ebp, esp.text:080484C8                 push    ebx.text:080484C9                 push    ecx.text:080484CA                 sub     esp, 20h.text:080484CD                 mov     eax, large gs:14h.text:080484D3                 mov     [ebp+var_C], eax.text:080484D6                 xor     eax, eax.text:080484D8                 mov     [ebp+var_24], 0.text:080484DF                 mov     [ebp+var_20], 0.text:080484E6                 sub     esp, 8.text:080484E9                 lea     eax, [ebp+var_24].text:080484EC                 push    eax.text:080484ED                 push    offset unk_80486B0.text:080484F2                 call    ___isoc99_scanf.text:080484F7                 add     esp, 10h.text:080484FA                 sub     esp, 8.text:080484FD                 lea     eax, [ebp+var_20].text:08048500                 push    eax.text:08048501                 push    offset unk_80486B0.text:08048506                 call    ___isoc99_scanf.text:0804850B                 add     esp, 10h.text:0804850E                 mov     ecx, [ebp+var_24] .text:08048511                 mov     edx, 55555556h.text:08048516                 mov     eax, ecx.text:08048518                 imul    edx.text:0804851A                 mov     eax, ecx.text:0804851C                 sar     eax, 1Fh.text:0804851F                 sub     edx, eax.text:08048521                 mov     eax, edx.text:08048523                 mov     [ebp+var_1C], eax.text:08048526                 mov     ecx, [ebp+var_20] .text:08048529                 mov     edx, 66666667h.text:0804852E                 mov     eax, ecx.text:08048530                 imul    edx.text:08048532                 sar     edx, 1.text:08048534                 mov     eax, ecx.text:08048536                 sar     eax, 1Fh.text:08048539                 sub     edx, eax.text:0804853B                 mov     eax, edx.text:0804853D                 mov     [ebp+var_18], eax.text:08048540                 mov     ecx, [ebp+var_20] .text:08048543                 mov     edx, 2AAAAAABh.text:08048548                 mov     eax, ecx.text:0804854A                 imul    edx.text:0804854C                 mov     eax, ecx.text:0804854E                 sar     eax, 1Fh.text:08048551                 sub     edx, eax.text:08048553                 mov     eax, edx.text:08048555                 mov     [ebp+var_14], eax.text:08048558                 mov     ecx, [ebp+var_20] .text:0804855B                 mov     edx, 38E38E39h.text:08048560                 mov     eax, ecx.text:08048562                 imul    edx.text:08048564                 sar     edx, 1.text:08048566                 mov     eax, ecx.text:08048568                 sar     eax, 1Fh.text:0804856B                 sub     edx, eax.text:0804856D                 mov     eax, edx

5.4 其它同理自己建立項目研究

自己建立項目研究,高手複習,新手學習,謝謝觀看。

看雪ID:TkBinary

https://bbs.pediy.com/user-home-723188.htm

  *本文由看雪論壇 TkBinary 原創,轉載請註明來自看雪社區。

相關焦點

  • 反彙編代碼還原之加減乘
    加法的高級代碼與反彙編而加法也特別簡單,配合上一篇講解的優化方式,可以很好的還原。加法對應的 彙編 **add** 指令.我不知道它人是否是這種反彙編風格,我是從下往上,按照上下文來進行還原。這種方法也很類似於 WG 找數據,從下向上找。
  • 高效的C編程之:除法運算
    14.2  除法運算  因為ARM體系結構本身並不包含除法運算硬體,所以在ARM上實現除法是十分耗時的。ARM指令集中沒有直接提供除法彙編指令,當代碼中出現除法運算時,ARM編譯器會調用C庫函數(有符合除法調用_rt_sdiv,無符合除法調用_rt_udiv),來實現除法操作。
  • 通過反彙編來理解restrict關鍵字
    在f中根據這兩個地址,將p和q分別設置為2和3,最後把p的值2當做函數返回值返回,並賦值給整形變量r。這個代碼很簡單,不過重點不是看它,而是它的反彙編代碼,下面我們通過objdump工具執行objdump -j .text -l -C -S test來生成彙編代碼。 首先來看下main函數的彙編代碼。
  • ARM彙編指令:.align理解和用法
    對齊偽指令ALIGN對齊偽指令格式:ALIGN Num其中:Num必須是2的冪,如:2、4、8和16等。,但是實際在執行中並不會按照預定的要求執行;編譯連結後,通過反彙編如下:30008000: e1a01000 mov r1, r030008004:
  • 智能合約安全系列文章反彙編·下篇
    前言上篇我們詳細分析了智能合約反彙編後的代碼內容,包括多個反彙編指令的含義,數據在棧中的存儲方式,並通過上下文關聯關係梳理代碼邏輯。本篇我們將繼續分析上篇遺留的反彙編代碼,通過上篇學習我們已對反彙編指令在棧和內存存儲的有了一定了解,該篇我們將重點來分析反彙編指令表示的代碼邏輯。
  • 各種開源彙編、反彙編引擎的非專業比較
    如果要對彙編指令進行分析和操作,要麼自己研究Intel指令集寫一個,要麼就用現成的開源引擎。自己寫太浪費時間,又是苦力活,還容易出錯,所以還是使用現成的好一點。  這裡對我曾使用過的比較流行的反彙編引擎做個比較,我使用過的反彙編引擎有:  1.
  • 51單片機彙編指令的記憶方法
    2 英文還原法單片機的操作碼助記符是該指令功能的英文縮寫,將縮寫還原成英語原文,再對照漢語有助於理解其助記符含義,從而加強記憶。2)Rn(n=0-7)、A、B、CY、DPTR寄存器尋址變量。3)@R0、@R1、@DPTR、SP表示寄存器間址變量。4)DPTR+A、PC+A表示變址尋址的變量。5)PC+rel(相對量)表示相對尋址變量。記住指令的助記符,掌握不同尋址方式的指令操作數的表示方法,為我們記憶彙編指 令打下了基礎。
  • DSP編程技巧之24---C/C++與彙編語言的交互之-(2)從C/C++代碼調用...
    2.使用內聯函數法調用彙編函數  這種方法一般用於引用單條的彙編語句,例如:  asm(";*** this is an assembly language comment");  上面例子並沒有影響任何的變量,它的作用只是在C/C++代碼編譯成彙編代碼之後,在相對應的位置插入了一端彙編代碼的注釋,對調試特別有幫助。
  • 解密入門教學(二)--彙編語言
    禁止製作和提供該軟體的註冊機及破解程序;禁止對本軟體進行反向工程,如反彙編、反編譯等")  作者這樣做,心情我們是可以理解的,畢竟人家花了那麼多心思在自己的軟體上,所以,我不希望你僅僅是因為交不起註冊費的原因來學習破解。
  • 彙編技術內幕(2)
    但如果反彙編Solaris/Linux的二進位文件,就會發現,都用EAX保存函數返回值。這不是偶然現象,是作業系統的ABI(Application Binary Interface)來決定的。Solaris/Linux作業系統的ABI就是Sytem V ABI。
  • 零時科技 | 智能合約安全系列文章反彙編·上篇
    本篇我們來一塊學習智能合約反彙編,同樣使用的是Online Solidity Decompiler在線網站,智能合約反彙編對於初學者來說,雖然較難理解,但只要能讀懂智能合約反彙編,就可以非常清晰的了解到合約的代碼邏輯,對審計合約和CTF智能合約都有非常大的幫助。
  • 逆向工程 | C 語言之 if-else 分支
    沒有刪減任何代碼,但是通過上面的代碼可知,確實有代碼被剪掉了。這正是Release版的強大之處,更確切地說應該是編譯優化的強大之處。看到這裡也許有的朋友會感到迷惑,我們如何才能將原來的代碼還原出來呢?答案是:還原不出來。Release版編譯出來的程序是不能還原出與原來完全相同的原始碼的,只能還原出功能相同的代碼。二、以變量為判斷條件的簡單if-else分支以Debug方式編譯後彙編代碼如代碼清單2所示。
  • 被除數、除數、商和餘數之和為629,用兩種方法求除數等於多少?
    被除數、除數、商和餘數之和為629,用兩種方法求除數等於多少?06 17:59 來源:讓你變得更聰明 原標題:被除數
  • 在C中嵌套彙編代碼難嗎?
    做底層軟體開發的,或多或少都會接觸一些彙編代碼,今天就來說說關於彙編在C中的定義和調用,以及舉例說明嵌套彙編代碼。有認真研究,或者說細心一點的讀者應該都知道:C中定義彙編代碼與編譯器有關。; Assembler Code Here#pragma endasm所以,你會發現,不同的編譯器,彙編代碼還是有差異
  • 除數為0會拋異常?不一定哦,來看這個
    想必大家都見過吧,在除數為0時就會拋出這個異常了。只要是除數為0就會拋出「java.lang.ArithmeticException: / by zero」這個異常嗎?如果我說不是,你相信嗎?來看下面的代碼。
  • 安全軟體公司Avast開源化機器碼反編譯器RetDec
    為了幫助安全社區對惡意軟體的逆向工程開展,著名安全軟體公司Avast宣布了研發7年的機器碼反編譯器RetDec的開源版本。 RetDec是可重定向的機器碼反編譯器,同時有在線反編譯服務和API ROPMEMU - 分析、解析、反編譯複雜的代碼重用攻擊的框架,能對常見和傳統的硬體架構的機器碼進行反編譯,支持ARM, PIC32, PowerPC以及MIPS架構的機器碼。目前開源版的RetDec源碼已經公布於GitHub網站上,RetDec現在也開始提供網頁服務。
  • Java代碼的編譯與反編譯
    2、用編譯程序產生目標程序的動作。 編譯就是把高級語言變成計算機可以識別的2進位語言,計算機只認識1和0,編譯程序把人們熟悉的語言換成2進位的。 編譯程序把一個源程序翻譯成目標程序的工作過程分為五個階段:詞法分析;語法分析;語義檢查和中間代碼生成;代碼優化;目標代碼生成。主要是進行詞法分析和語法分析,又稱為源程序分析,分析過程中發現有語法錯誤,給出提示信息。
  • 專欄:ACM算法面面觀[4]-快速冪
    遞歸快速冪的思路非常自然,代碼也很簡單(直接把遞歸方程翻譯成代碼即可)://遞歸快速冪int qpow(int a, int n){ if (n == 0) return 1; else if (n % 2 == 1) return qpow(a, n - 1) * a;
  • 混合使用C、C++和彙編語之:內聯彙編和嵌入型彙編的使用
    例如,在下面幾種情況中必須使用內聯彙編或嵌入型彙編。·程序中使用飽和算術運算(Saturatingarithmetic),如SSAT16和USAT16指令。·程序中需要對協處理器進行操作。·在C或C++程序中完成對程序狀態寄存器的操作。使用內聯彙編編寫的程序代碼效率也比較高。
  • 0竟然不能做除數
    比如,如何區分2和20,或17、107和170?公元5世紀,因此古印度人發明了表示「無」的符號「0」,將之命名為「」,意思就是「空」。對於哲學來說,0 ,就是無,也就是無中生有的那個無,道家講的「道」,佛家講的「空」,它是一切的本元,不是通常意義上的什麼都沒有,而恰恰是世界萬物生發之初,是根源,是已知和未知世界的全部。