ARM/THUMB汇编(补丁开发类)基础教程
生活随笔
收集整理的這篇文章主要介紹了
ARM/THUMB汇编(补丁开发类)基础教程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、匯編基礎
(1)、ARM與THUMB
匯編是與C語言掛鉤的,沒有C語言基礎,很難學匯編。索尼愛立信的固件主要用的是THUMB指令,當然還有小部分是ARM指令。如何區分THUMB和ARM指令呢?在IDA中,一段函數反匯編后,機器碼最小是2的就是THUMB指令,機器碼最小是4的就是ARM指令,ARM在IDA中表示為CODE32,THUMB在IDA中表示為CODE16。當我們確定好該函數是ARM還是THUMB,就可以開始反了。(以下反匯編都是隨便從某個地址中開始反,因為這樣在實際中比較常見,很少有人把整個固件反的。)由于我們在固件的開頭按了alt+g,選“1”,也就是說默認的是THUMB指令,可是當我們反到一個函數是ARM指令的怎么辦呢?按alt+g選“ROM”即可繼續按C反匯編。另外,再給一些經驗就是ARM指令的機器碼有個規律,都是“??,??,??,E?”形式的,這樣好辨認了吧。
(2)、寄存器
ARM模式:
一般通用寄存器:R0~R12
堆棧指針:R13
鏈接寄存器:R14
程序計數器:R15
THUMB模式:
一般通用寄存器:R0~R7
堆棧指針:SP
鏈接寄存器:LR
程序計數器:PC
(3)、基本指令
(我以asm補丁比較常見的為例)
MOV:賦值指令
MOV R1,0x6
翻譯成C語言就是R1=0x6;
簡單吧,但是MOV的立即值是有范圍的,在0~0xFF之間。如果我要賦的值大于0xFF怎么辦?看下面
MOVL:賦值指令
MOVL R1, 0xFB0
翻譯成C語言就是R1=0xFB0;
當然這個MOVL也是有范圍的,不能大于0xFFF。可是問題來了,如果我要賦的值大于0xFFF怎么辦?看下面
LDR:裝載指令
LDR R0, dword_label
……
(這里可以很遠很遠,也可以很近很近)
……
dword_label dw 0x6FFFFFFF
說明:這里“dword_label”只是一個標記,你想神馬名字都可以的
ADD:加法指令
ADD R1, R0, 0
翻譯成C語言就是R1=R0+0;
咦,這樣不是把R0的完全不變傳遞到R1了么?沒錯,就是這樣子的。
SUB:減法指令
SUB SP, SP, 0x8
翻譯成C語言就是SP=SP-0x8;
LSL:左移指令
LSL R7, R7, 2
翻譯成C語言就是R7=R7<<2;
LSR:右移指令
LSR R0, R0, 0x14
翻譯成C語言就是R0=R0>>0x14;
CMP:比較指令
CMP R1, 0
翻譯成C語言就是if(R1!==0)
一般下面都會有BEQ、BNE的。BEQ執行的是條件成立的事件,BNE執行的是條件不成立的事件。
B:跳
有點像C語言里面那個go to,總之就是跳到某個地方,當然這個跳是有范圍限制的,具體我也不清楚。超出范圍的話,ARM PC會提示超出范圍。如果需要跳到很遠很遠的地方,比如一般的占用補丁,都是一下這種類型的。
LDR R3, out_1
BLX R3
out_1 dw outout_1+1
BL:帶返回的跳
一般的執行函數都是用BL來執行的。
BX:帶切換的跳
比如原先是ARM模式,跳過去就是THUMB模式;反之,原先是THUMB模式,跳過去就是ARM模式。
BLX:帶返回帶切換的跳
其實就是BL的基礎上加一個帶返回的功能,3350平臺調用函數一般用這個。
二、看懂匯編
好,接下來,我們來隨便寫句簡單的語句。
STRID s=STR(“你好”);
上面的看不懂請先學習如何編寫ELF,謝謝。
提示:在include/Types.h里面
#define STR(__STR__) Str2ID(_T(__STR__),0,SID_ANY_LEN)
#define _T(__STR__) L##__STR__
#define SID_ANY_LEN 0xFFFF
其實翻譯一下就是STRID s =Str2ID(L”你好”,0, 0xFFFF);
第二個參數0代表wchar_t,5代表數組,6代表char。(PS:某種類型補丁漢化就是把6改0)
OK,現在開始用匯編編寫這句。
LDR R0,dword_string
MOV R1,0
LDR R2,dword_anylen
BL Str2ID
dword_string db 0x60,0x4F,0x7D,0x59,0,0
dword_anylen dw 0xFFFF
一開始,R0存的是“你好”,匯編要轉成Unicode。R1存的是0,R2存的是0xFFFF,恰好,R0是Str2ID的第一個參數,R1是Str2ID的第二個參數,R2是Str2ID的第三個參數。然后BL執行函數,執行完之后,不是有返回值(STRID)s么?是的,BL執行完之后,R0存的就是(STRID)s了,其它函數也是這個道理。從此以后,就是可以開始在固件中找函數了。
三、匯編函數
大家移植LIB的話會發現,函數有個共同點,就是以PUSH開始,POP結束。還有一個共同點就是PUSH后面一定有LR,POP后面一定有PC。PUSH叫入棧,POP叫出棧。還是舉例來說。
(1)、保護寄存器
PUSH {R1-R3,LR}
把R1,R2,R3,LR入棧,入棧前R1,R2,R3存的值,會在
POP {R1-R3,PC}
之后恢復。
(2)、局部變量
寫過函數都知道,函數里面是可以有局部變量的。
PUSH {R1-R3,LR}
入棧了四個寄存器,也就是說函數里面預留了0x4*0x4=0x10字節的空間,可以存4個int型的變量。如果我需要的局部變量更多,那就要用指針了。假如這個函數需要5個int型的局部變量,入棧里面差一個,可以PUSH多一個寄存器,但是我們沒必要還原那個寄存器。可以這樣,在PUSH后
SUB SP, SP, 0x4
POP前
ADD SP, SP, 0x4
即可。
一、匯編基礎
(1)、ARM與THUMB
匯編是與C語言掛鉤的,沒有C語言基礎,很難學匯編。索尼愛立信的固件主要用的是THUMB指令,當然還有小部分是ARM指令。如何區分THUMB和ARM指令呢?在IDA中,一段函數反匯編后,機器碼最小是2的就是THUMB指令,機器碼最小是4的就是ARM指令,ARM在IDA中表示為CODE32,THUMB在IDA中表示為CODE16。當我們確定好該函數是ARM還是THUMB,就可以開始反了。(以下反匯編都是隨便從某個地址中開始反,因為這樣在實際中比較常見,很少有人把整個固件反的。)由于我們在固件的開頭按了alt+g,選“1”,也就是說默認的是THUMB指令,可是當我們反到一個函數是ARM指令的怎么辦呢?按alt+g選“ROM”即可繼續按C反匯編。另外,再給一些經驗就是ARM指令的機器碼有個規律,都是“??,??,??,E?”形式的,這樣好辨認了吧。
(2)、寄存器
ARM模式:
一般通用寄存器:R0~R12
堆棧指針:R13
鏈接寄存器:R14
程序計數器:R15
THUMB模式:
一般通用寄存器:R0~R7
堆棧指針:SP
鏈接寄存器:LR
程序計數器:PC
(3)、基本指令
(我以asm補丁比較常見的為例)
MOV:賦值指令
MOV R1,0x6
翻譯成C語言就是R1=0x6;
簡單吧,但是MOV的立即值是有范圍的,在0~0xFF之間。如果我要賦的值大于0xFF怎么辦?看下面
MOVL:賦值指令
MOVL R1, 0xFB0
翻譯成C語言就是R1=0xFB0;
當然這個MOVL也是有范圍的,不能大于0xFFF。可是問題來了,如果我要賦的值大于0xFFF怎么辦?看下面
LDR:裝載指令
LDR R0, dword_label
……
(這里可以很遠很遠,也可以很近很近)
……
dword_label dw 0x6FFFFFFF
說明:這里“dword_label”只是一個標記,你想神馬名字都可以的
ADD:加法指令
ADD R1, R0, 0
翻譯成C語言就是R1=R0+0;
咦,這樣不是把R0的完全不變傳遞到R1了么?沒錯,就是這樣子的。
SUB:減法指令
SUB SP, SP, 0x8
翻譯成C語言就是SP=SP-0x8;
LSL:左移指令
LSL R7, R7, 2
翻譯成C語言就是R7=R7<<2;
LSR:右移指令
LSR R0, R0, 0x14
翻譯成C語言就是R0=R0>>0x14;
CMP:比較指令
CMP R1, 0
翻譯成C語言就是if(R1!==0)
一般下面都會有BEQ、BNE的。BEQ執行的是條件成立的事件,BNE執行的是條件不成立的事件。
B:跳
有點像C語言里面那個go to,總之就是跳到某個地方,當然這個跳是有范圍限制的,具體我也不清楚。超出范圍的話,ARM PC會提示超出范圍。如果需要跳到很遠很遠的地方,比如一般的占用補丁,都是一下這種類型的。
LDR R3, out_1
BLX R3
out_1 dw outout_1+1
BL:帶返回的跳
一般的執行函數都是用BL來執行的。
BX:帶切換的跳
比如原先是ARM模式,跳過去就是THUMB模式;反之,原先是THUMB模式,跳過去就是ARM模式。
BLX:帶返回帶切換的跳
其實就是BL的基礎上加一個帶返回的功能,3350平臺調用函數一般用這個。
二、看懂匯編
好,接下來,我們來隨便寫句簡單的語句。
STRID s=STR(“你好”);
上面的看不懂請先學習如何編寫ELF,謝謝。
提示:在include/Types.h里面
#define STR(__STR__) Str2ID(_T(__STR__),0,SID_ANY_LEN)
#define _T(__STR__) L##__STR__
#define SID_ANY_LEN 0xFFFF
其實翻譯一下就是STRID s =Str2ID(L”你好”,0, 0xFFFF);
第二個參數0代表wchar_t,5代表數組,6代表char。(PS:某種類型補丁漢化就是把6改0)
OK,現在開始用匯編編寫這句。
LDR R0,dword_string
MOV R1,0
LDR R2,dword_anylen
BL Str2ID
dword_string db 0x60,0x4F,0x7D,0x59,0,0
dword_anylen dw 0xFFFF
一開始,R0存的是“你好”,匯編要轉成Unicode。R1存的是0,R2存的是0xFFFF,恰好,R0是Str2ID的第一個參數,R1是Str2ID的第二個參數,R2是Str2ID的第三個參數。然后BL執行函數,執行完之后,不是有返回值(STRID)s么?是的,BL執行完之后,R0存的就是(STRID)s了,其它函數也是這個道理。從此以后,就是可以開始在固件中找函數了。
三、匯編函數
大家移植LIB的話會發現,函數有個共同點,就是以PUSH開始,POP結束。還有一個共同點就是PUSH后面一定有LR,POP后面一定有PC。PUSH叫入棧,POP叫出棧。還是舉例來說。
(1)、保護寄存器
PUSH {R1-R3,LR}
把R1,R2,R3,LR入棧,入棧前R1,R2,R3存的值,會在
POP {R1-R3,PC}
之后恢復。
(2)、局部變量
寫過函數都知道,函數里面是可以有局部變量的。
PUSH {R1-R3,LR}
入棧了四個寄存器,也就是說函數里面預留了0x4*0x4=0x10字節的空間,可以存4個int型的變量。如果我需要的局部變量更多,那就要用指針了。假如這個函數需要5個int型的局部變量,入棧里面差一個,可以PUSH多一個寄存器,但是我們沒必要還原那個寄存器。可以這樣,在PUSH后
SUB SP, SP, 0x4
POP前
ADD SP, SP, 0x4
即可。
總結
以上是生活随笔為你收集整理的ARM/THUMB汇编(补丁开发类)基础教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【系统设计】发现类的方法
- 下一篇: 【计算机网络】链路与连通