Jlink可以將Hex文件下載到單片機內(nèi),也可以將未加密單片機內(nèi)部的程序文件讀出。本篇文章介紹,如何使用JFlash來讀取單片機的程序,學(xué)習(xí)單片機程序文件的讀取,不是為了破解別人的程序,而是學(xué)習(xí)破解的原理,從而更好保護自己的程序不被破解,希望大家也能尊重他人的勞動成果。
JFlash的下載和安裝
首先,安裝JFlash軟件,安裝完成后,會默認安裝JLink驅(qū)動程序,主要包含以下幾個工具:- JFlash,主要用于程序下載和讀取。
- JFlashLite,JFlash的Mini版
- JFlashSPI,用于給SPI存儲器下載程序,如W25Q128。
- JLinkGDBServer,用于第三方軟件的調(diào)試器,如使用Eclipse搭建STM32開發(fā)環(huán)境時,就要使用GDB Server來進行調(diào)試。
- JLink Command,命令操作窗口,輸入指令執(zhí)行連接,擦除、下載、運行等操作。
軟件準備
- Jlink軟件,J-Flash
- Jlink調(diào)試器,如Jlink V9
- 單片機開發(fā)板,如STM32F103RET6
1.打開JFlash
2.創(chuàng)建新工程
點擊 File->NewProject3.選擇芯片的型號
這里支持很多ARM Cortex內(nèi)核的芯片,選擇要讀取單片機對應(yīng)的芯片型號,我這里選擇的是STM32F103RE系列。4.連接芯片
如果選擇的是SWD模式,就要連接SWDIO、SWCLK、GND這三根線,連接好之后,點擊Target->Connect,如果連接成功,在下面的LOG窗口會顯示連接成功。5.讀取單片機內(nèi)的程序
重點來了!選擇Target->Manual Programming ->Read Back,一共有三個選項,用于讀取不同的Flash地址范圍。- Selected sectors
- Entire chip
- Range
6.保存讀取到的程序
選項File-> Save data file或者是Save data file as,保存類型根據(jù)需要選擇,建議選擇Hex格式,已經(jīng)包含了地址信息。7.程序的驗證。
怎么驗證讀取到的程序是正確的呢?很簡單,重新燒寫進去,看運行現(xiàn)象和原來的是不是一樣就行了。具體操作方法查看上一篇Jlink系列文章:Jlink使用技巧之單獨下載HEX文件到單片機總結(jié)
既然能這么簡單的讀取到單片機的程序,那么我們自己的程序應(yīng)該如何保護起來呢?很顯然,我們可以對Flash設(shè)置讀保護功能,即大家說的“加密”功能,可以防止對Flash的非法訪問,這里的加密是針對整個Flash區(qū)域的,如果設(shè)置了讀保護功能,那么程序只能正常的從RAM中加載運行,而不能通過調(diào)試器讀出來,那么別人就不能破解了。哈哈!具體怎么實現(xiàn)呢?這里先介紹幾個關(guān)于Flash保護操作的幾個庫函數(shù):FLASH_Unlock(); ? //Flash解鎖
FLASH_ReadOutProtection(DISABLE); ?//Flash讀保護禁止 ?
FLASH_ReadOutProtection(ENABLE); ? //Flash讀保護允許
void Set_Protect(void)
{
? ?if(FLASH_GetReadOutProtectionStatus() != SET)
? ?{
? ? ? ?FLASH_Unlock();
? ? ? ?FLASH_ReadOutProtection(ENABLE);
? ? ? ?FLASH_Lock();
? ?}
}
- 啟動讀保護后,就不能讀寫程序了,如使用JLink讀取程序,或者是重新下載程序。
- 所以,在下載程序之前,需要通過程序內(nèi)部調(diào)用關(guān)閉讀保護,關(guān)閉讀保護之后,會自動清空Flash
- 另外,當?shù)谝淮握{(diào)用SetProtect()函數(shù)啟動讀保護之后,不能再次調(diào)用OffProtect()函數(shù)關(guān)閉讀保護,需要重新斷電才能關(guān)閉讀保護
void Off_Protect(void)
{
? ?if(FLASH_GetReadOutProtectionStatus() != RESET)
? ?{
? ? ? ?FLASH_Unlock();
? ? ? ?FLASH_ReadOutProtection(DISABLE);
? ? ? ?FLASH_Lock();
? ?}
}
int main(void)
{
? ?/*用戶代碼*/
? ?if(KEY == 0) ? ? ? ?//按鍵按下
? ?{
? ? ? ?Off_Protect();
? ?}
? ?else
? ?{
? ? ? ?Set_Protect();
? ?}
? ?/*用戶代碼*/
? ?while(1)
? ?{
? ?/*用戶代碼*/
? ?}
}