有一天在網上下載了一個上個世紀DOS年代的光盤ISO,裡面有一個README.EXE的DOS可執行文件,在過去,這一般是光盤裡面的軟件說明。
好奇想知道這光盤裡面有一些什麼軟件,于是執行README.EXE,由于是虛拟機裡面執行所以也不擔心有病毒。執行的結果有點意外,文件竟然設置了訪問密碼。
設置了訪問密碼的README.EXE
這反而更好奇這個文件裡面的内容了。
疫情在家遊戲玩多了,不妨把破解密碼的過程當作是一次解迷遊戲,于是決定花點時間嘗試對這個程序的訪問密碼進行破解。
為什麼這些光盤說明不放在一個文本文件裡呢?因為這是要方便沒有中文DOS環境的用戶查看,因此有人會用工具生成一個可以顯示這些中文說明的DOS的EXE文件。
在動手破解之前,要先介紹一些背景和破解思路。
先說背景知識:
小型的DOS程序一般都是彙編語言開發,生成機器碼比較精簡相對容易用debug工具跟蹤,而對于所謂密碼的處理一般不會像現在這樣用DES、AES、RC4對密碼進行加密,通常就是設一個字符串然後和用戶輸入的字符進行比較,如果字符串匹配上就繼續執行,匹配不上就退出程序。
如果是用BASIC或者其他高級語言開發編譯的程序生成的機器代碼就相對複雜。
有一些防破解的DOS軟件會對自身進行加密,加載到内存後先做解密再去執行,對于這類程序要先經過一種叫“脫殼”過程後才可以跟蹤,破解也就不那麼容易。
說完背景知識就說破解思路:
先在Linux用 strings 查看程序裡面字符,看看有沒疑似密碼的字符串,經過嘗試沒發現找到像明文的密碼字符串,看來密碼不是以明文方式存放在程序裡面的。
既然密碼不是以明文方式存放的,那麼怎麼找到密碼呢?
我想起我朋友和我說過他開發的軟件是怎麼被一個外國人破解的過程,朋友的軟件需要用戶輸入注冊碼,因為在用戶輸入注冊碼之後,程序就要對注冊碼進行校驗并根據校驗的結果進行分支跳轉,因此隻要追蹤程序彈出注冊碼的對話框或者是提示注冊碼成功/失敗的信息的機器代碼就能非常接近破解的目标,這時可以分析存放在内存中密碼,如果破解密碼很麻煩也可以用彙編語言修改内存中的機器指令,即使注冊碼校驗不過也強制跳轉到注冊碼校驗成功的程序分支。
于是這裡有了兩個方案,
方案一:
跟蹤程序顯示 “Please input password:” 或 “Invalied password!” 的代碼,找到對比密碼字符串的代碼這樣就有可能找到存放密碼的内存地址從而把密碼找出來。
方案二:
如果程序對密碼的處理過程比較複雜,例如用了一些加密算法,即使找到存放密碼的内存地址也不太容易分析出密碼,那麼還可以跟蹤跳轉到顯示 “Invalied password!” 的分支代碼,修改跳轉的指令使得即使密碼校驗不正确也跳轉到密碼校驗成功的代碼分支上去。
用到的調試工具是DOS下的 debug,裡面有内存搜索的指令可以搜出程序中調用顯示字符串的彙編代碼。
在DOS的字符界面上顯示字符串有三種方式
1、直接寫顯卡内存B800
2、調用BIOS 中斷 int 10H
3、調用DOS 中斷 int 21H
從程序滾動輸出這些字符串來看,一般不會是用直接寫顯存的方式去實現,如果要這樣做就要實現拷貝内存和操作顯卡寄存器一整套功能,而這裡僅是簡單顯示一些字符串,因此先排除直接寫顯卡内存。
經過搜索跟蹤,排除了調用BIOS 中斷 INT 10H,這個過程略過細節,大約過程就是去找,但沒找到。
剩下就是跟蹤調用DOS 中斷 INT 21H顯示字符串這條線索,下面是詳細的過程。
用 DOS INT 21H 顯示字符串的過程大概是這樣:
把以$為結束符的字符串的地址放到寄存器DS:DX裡,把寄存器AH設為09, 09是DOS INT 21H功能号,用于顯示DS:DX存放的地址的内容,最後調用 INT 21H,這樣DOS就會在當前光标的位置顯示這個字符串。
因此,我們隻需用debug把 README.EXE 加載到内存後搜索哪裡有 MOV AH,09 和 INT 21H 這兩條指令,這樣就能比較容易找到輸出字符串的地方。
當然了,如果程序裡大量使用INT 21H輸出字符串,那就會搜索很多條結果出來,這時就要先搜索 “Please input password:” 和 “Invalied password!” 這兩個字符串在内存裡面的地址,然後搜出加載這些字符串地址到DS:DX的代碼,這樣可以縮小跟蹤分析的範圍。
DOS 的 debug 的 s 命令可以用16進制或 ASC碼 搜索内存,而我們不大可能記得 INT 21H 這條彙編指令對應的X86 CPU的機器指令,因此可以用 debug 的彙編功能先輸入INT 21H,然後反彙編看這條指令對應的機器指令。
使用debug的彙編和反彙編命令
這裡可以看到 INT 21H 對應的x86 CPU 機器指令用16進制表示是 CD21,MOV AH,09 對應的機器指令是B409。
有了這些準備,就可以開始用debug破解這個程序了,先用debug加載 README.EXE,然後用 r 指令查看當前的寄存器,其中
CS=121F
IP=0100
這表示CS寄存器的内容是 121F IP 寄存器為0100,這表明 README.EXE 的代碼段被加載到段地址為121F,偏移地址為0100 這個地方,如果不清楚這裡的意思的話,可以查資料去了解一下 intel x86 CPU 在16位實模式下内存尋址方式。
在這裡,隻需要記得README.EXE的代碼就在這個區域裡面,先重點對這個區域搜索。對于一些大型的DOS程序,程序和數據可能會分布在多個段裡,這樣就不能隻搜索一個段了。
分别輸入搜指令
-s 121F:0100 FFFF B4 09
-s 121F:0100 FFFF CD 10
使用debug的搜功能
符合條件的地址會被列出來,根據搜索的結果可以看到,
在 121F:01B8 和 121F:01F3 這兩個地方有機器碼B409(MOV AH,09) ,而121F:01BD和121F:01F8有機器碼 CD10(INT 21H),這兩組地址(121F:01B8和121F:01BD,121F:01F3和121F:01F8)靠得很近,這是很關鍵的線索,根據這個信息可以初步判斷121F:01BD和121F:01F8這兩個地方的代碼調用了DOS 21H顯示字符串。
這時可以用 debug 的 u 命令反彙編代碼看一下。
用debug的反彙編和内存查看功能
-u 121F:01F3
從反彙編的結果可以看到,這個确實是一段調用DOS 21H顯示字符串的代碼,要顯示的字符串的段偏移地址是 0263 ,在顯示完這字符串之後,就調用 INT 21的4C号(MOV AH,4C 和 INT21H)功能退出了程序。
沒有看到操作DS寄存器的内容,這有可能是數據可以代碼都在同一個段裡(121F)
上圖中用 debug d指令查看了121F:0263地址内容,看到了這塊内存保存字符串“Invalied password!”。
到這裡,就開始有點接近目标了,這裡就是校驗密碼失敗後退出程序的地方,再往上一點代碼,應該就是密碼校驗的地方,在被那就有可能找到密碼存放的地方。
這時就需要一點一點對121F:01F3(B409 MOV AH,09)前面的地址進行反彙編,由于intel x86 CPU的指令不是定長的,因此選定的反彙編起始地址不對可能會得到不正确的指令。
用debug反彙編 121F:01CE處的代碼
用 u 命令一直往前反彙編,在 121F:01CE 這個地方可以看到調用了DOS 21H的07号功能,這段代碼是讀取鍵盤輸入的内容到寄存器AL,然後将AL的内容和 0xF0 這16進制數進行XOR運算結果保存到AL,最後把寄存器AL的内容保存到寄存器 SI 指向的内存地址。
這樣看來,密碼可能與 F0 做過XOR運算,因此隻需要找到内存中的密碼,用XOR就能還原出密碼來。
繼續往下反彙編
用debug反彙編121F:01E3處的代碼
這裡可以看到,這是一段字符串比較的代碼,具體的細節可以查 intel 彙編語言,這裡大概的意思就是把内存 0107 (沒有指明段地址,默認還是121F)裝載到寄存器CL,REPZ CMPSB 會根據 CX(CH被XOR指令設為0) 的值作為循環的次數比較SI 和 DI 指向的内存,每比較一個字符串,就SI、DI寄存器就加1,CX寄存器就減1。
MOV SI,0108
MOV DI,028D
毫無疑問,這裡此時SI和DI保存的就是鍵盤輸入的口令和程序預設密碼的内存地址,至于預設密碼的地址保存在SI還是DI,這可以往前反彙編查看鍵盤輸入的口令保存在位置,這樣可以反推出密碼存放的地址。
在這程序裡,從代碼中可以看到,SI初始化為0108 (沒有指明段地址,默認還是121F),而0107保存了要比較的字符串的長度,因此有理由判斷密碼可能保存在 121F:0108 這個地方。
于是執行debug 的d指令查看 121F:0107
用debug查看内存
這裡可以看到0107處的内存是04,後面跟着4個C2,這裡就可以比較肯定的判斷,密碼長度是4,密碼的内容是4個C2,當然這密碼是和前面提到 0xF0 進行XOR運算的結果。
現在,就開始嘗試還原密碼用計算器或者上網随便找個進制轉換的網頁進行進制轉換。
換算的結果是
F0的二進制表示為11110000
C2對應的二進制是11000010
把 11000010 和 11110000做 XOR 運算得到
11110000
11000010 xor
00110010
得到的結果是 00110010,轉換為16進制是0x32,通過查ASC碼表得到對應的字符是'2',就是說密碼是"2222"。
退出debug,再次執行README.EXE,輸入密碼 2222,最後密碼校驗通過,顯示出裡面的内容。
密碼校驗通過後顯示的内容
至此,這個來自上世紀的密碼就被破解了。
從文件的内容看光盤裡面存放是軟盤鏡像IMG格式文件,這有可能當時電腦店用的光盤,那時還沒有電腦城,可每個城市會有一兩家電腦店,日常除了賣電腦給單位外,還會賣一些軟件拷貝給用戶,那時光驅還沒普及,也沒有U盤和移動硬盤,拷貝軟件一般用軟盤,所以這些軟件一般是用軟盤鏡像IMG格式存放在光盤裡,用戶根據目錄選好要拷貝的軟件後,店員就會用HD-COPY這個軟件從光盤上拷貝到用戶的軟盤上,我還記得當時是10元拷貝一張軟盤。
為什麼這些軟件的軟盤鏡像文件會放在光盤上呢?這是因為當時電腦的硬盤空間極少有超過1GB的,通常的都是幾百MB,甚至一些電腦是沒有硬盤的,而一張光盤有600多MB,一家電腦店通常會有十幾張這樣的光盤,裡面有操作系統,漢字系統,字處理軟件,工具軟件,遊戲也是極少的,即使有遊戲也是很簡陋也不好玩的遊戲,好玩的遊戲要等光驅開始普及的時候才看到。
從列出的軟件來看,這張光盤應該比較後期的了,而這個密碼可能是印在光盤的封面上的,也或許是這種光盤最初是在電腦店之間流通,加上密碼可能是為了保護光盤的制作人的利益。
到光驅開始普及後,在市面上也能賣到這種裝滿軟件光盤,但逐漸的裡面的軟件就是直接放在目錄裡面,不用做成軟盤鏡像格式了,因為方便用戶就直接在光盤運行軟件的安裝程序。
最後說一下,這個 README.EXE 其實不是用彙編語言開發,至少不是全部是用彙編開發的,在一開始在Linux下用strings檢查文件的時候看到了 "Borland" "Turbo-C"的字樣,Borland的C編譯器在當時很出名,可以生成很精簡的高質量的機器碼,因此用debug跟蹤下來比較順利。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!