可執行檔編碼程式 (.COM 篇)
本帖最后由 zenix 于 2009-4-15 11:19 编辑原創於 1997 年07月07日, 首次刊於台灣旗標的 Run!PC 雜誌.
有人看了二, 要我把一也發上來. 努力一找, 還真找到了.
這個技巧一不是破解, 而是保護 CRYPTCOM.ASM可執行檔編碼器 (.COM 格式)的編寫教學.
也就是 FSE 的原型. 附件是編排好一點的 PDF
┌───────────────────────────────┐
│ 個人基本資料 │
├───────────────────────────────┤
│ 姓名 : 楊旭峰 │
│ 身份證字號: ********** │
│ 通訊地址: ********************************************* │
│ 戶籍地址: *********************************** │
│ 聯絡電話: (**)***-**** (公司) │
│ (**)***-**** (家裡) │
└───────────────────────────────┘
以上為投稿內容:
本文件內容為 PE2 所打, 未經重新編排修飾.
如蒙採用, 我每個月寫個兩三篇也沒問題....
╒═════╤═══════════════════════════════
│[技術空間]│
╘═════╛
保護與破解的攻防技巧(一):
可執行檔編碼程式 (.COM 篇)
/ 楊旭峰
zenix@ms10.hinet.net
再過幾天就是聖誕節了, 為了和他共渡一段浪漫的假期, 決定儘早把
這份電腦作業給完成. 我可不希望在浪漫的時刻還在擔心作業交不出來啊!
真是一個殘酷的聖誕節, 趕剛完的程式還未打上註解, 哦! 明天還要
上台報告. 時間為什麼總是不夠用? 知識總是學不完.
回想當初為什麼會寫這個程式呢? 記得從玩電腦開始, 最可怕的工具軟
體就是 PcTools. V4.XX 版, 相信今天用它的人還很多. 這一類的軟體可
以讓使用者輕易地修改任何檔案內容. 功力好的人就拿來修改程式碼, 以
破解軟體的保護, 功力差的人也能利用它來輕易地修改版權畫面. 而當時
功力差的人居多, 因此隨處可見被篡改的版權畫面. 真不知他們這樣子做
的樂趣在哪裡?
有一天出現了一種叫做可執行檔壓縮器. 這種工具軟體可以把可執行
檔壓縮, 而且壓縮後的檔案仍然可以正常執行. 更令軟體商心動的是, 壓
縮後的檔案內容是編碼過的, 和原來內容不一樣, 似乎可以有效地防止被人
『輕易』地篡改. 但是用過的人都知道壓縮檔的內容並未完全加密, 因此
很多時候部份的檔案內容是和原來相同的. 所以如果我們真正需要的是完
全編碼而非部份編碼的話, 那麼我們何不來自己做一個編碼器?
可執行檔編碼器在以前真可謂是『不傳之秘』. 連原理都沒有人願意
透露, 原因我想大家多少也都知道一些吧! 在此我們先就 .COM 檔來做一
個編碼器! 在開始之前, 我們必須先來了解一下 .COM 檔. 在此我並不打算
探入探討像 PSP結構之類的問題, 僅告訴你我們需要的最基本概念即可.
┌───────────────────┐
│.COM 檔的特性: │
├───────────────────┤
│(1). 程式載入時: CS=DS=ES=SS │
│ IP=100h │
│ SP=FFFE │
│(2). 檔案長度小於 64 K (10000h Byte)│
│(3). 沒有檔頭, 也沒有重定位表. │
└───────────────────┘
接下來我們該怎麼著手呢? 先看看一般病毒的作法吧! 如果我們大略
地看一下被感染檔案的程式碼, 它是像這個樣子.
┌────────────────────────────┐
│Start: │
│ jmpVirus ;; 原來這裡的 3 Byte 被改成這樣 │
│ ..... │
│ .....這裡是原程式 │
│ ..... │
│Virus: │
│ 做病毒該做的事 以及 還原最前面的 3 Byte │
│ 回到 Start │
└────────────────────────────┘
病毒為了減少磁碟寫入時間, 會先保留原程式最開頭的 3 - 4 Byte,
然後僅寫入最開頭的 jmp virus 或 call virus, 然後在 virus 的程式
碼中再還原程式的最開頭. 可是我們可以不必這麼做.
為求一切從簡, 我們決定把我們編碼器做出來的檔案分成三部份:
[跳躍指令(到解碼段)] + [編碼過後的原程式] + [解碼及返回]
格式訂定如下:
┌────────────────────┐
│Start: │
│ pusha ;; 保留暫存器的值 │
│ jmp Decoder │
│ ..... │
│ .....這裡是編碼過後的原程式 │
│ ..... │
│Decoder: │
│ 解碼 │
│ popa ;; 還原暫存器的值 │
│ 回到 Start │
└────────────────────┘
第一部份『jmp Decoder』, 組譯後的程式碼為 0e9h, ????h.
但這 ????h 的值是多少呢? 沒錯, 就是原程式的總長度.
第三部份的最後『回到 Start』, 我們要怎麼做呢? 我們知道Start的
IP值為 100h, 如果我們不要變動任何節區暫存器的話, 那麼我們可以簡單
地用這兩行來返回 Start
┌─────┐
│push 100h │
│ret │
└─────┘
再來是解碼部份. 這一部份我們一定要和編碼部份配合, 否則解不回原來
的碼就糟糕了. 在編碼及解碼方面, 這一次我們使用 XOR 來做.因為一個
數對另一個值做 XOR 運算兩次的結果會回到原來的值. 底下就是我們寫好
的第一個可執行檔編碼器:
>> ======== 從下一行開始 ==========
;; ┌─────────────────────────────╖
;; │檔名: CRYPTCOM.ASM可執行檔編碼器 (.COM 格式) ║
;; │版本: 1.0 ║
;; │日期: 1997-12-20 ║
;; │組譯: TASM CRYPTCOM.ASM ║
;; │ TLINK /t CRYPTCOM ║
;; │ ║
;; │作者: 楊旭峰 Zenix Yang zenix@ms10.hinet.net ║
;; ╘═════════════════════════════╝
.MODEL TINY
.CODE
.286c
ORG 100h
Start:
callShow_Logo ;; 顯示標題
callOpen_Input_File ;; 開啟 IN.COM
callCreate_Output_File ;; 建立 OUT.COM
callRead_Body ;; 讀取 IN.COM 的內容
callEncrypt_Body ;; 對所讀取的內容編碼
callWrite_Output_File ;; 產生編碼後的 OUT.COM
jmp End_All ;; 結束了
;;--------------------------------------------
;; 顯示標題
;;--------------------------------------------
Show_Logo PROC near
movah, 09h
movdx, OFFSET msg_Logo
int21h
ret
endp
;;--------------------------------------------
;; 開啟 IN.COM
;;--------------------------------------------
Open_Input_File PROC near
movah, 3dh
moval, 0h ;; AL=0, 以唯讀方式開啟檔案
movdx, OFFSET input_file
int21h
jc Error_Open ;; 開啟檔案失敗嗎?
movinput_handle, ax ;; 把 IN.COM 的檔案代碼存起來
ret
;; --------------------------------
;;開啟或建立檔案失敗了就來這裡
;; --------------------------------
Error_Open:
movah, 09h
movdx, OFFSET msg_error_open
int21h
movah, 4ch
int21h
endp
;;--------------------------------------------
;; 建立 OUT.COM
;;--------------------------------------------
Create_Output_File PROC near
movah, 3ch
movcx, 0h
movdx, OFFSET output_file
int21h
jc error_open ;; 建立檔案失敗嗎?
movoutput_handle, ax ;; 把 OUT.COM 的檔案代碼存起來
ret
endp
;;--------------------------------------------
;; 讀取 IN.COM 的內容
;;--------------------------------------------
Read_Body PROC near
movah, 3fh
movcx, 0F000h ;; 我們這裡只處理長度小於
;; 61,440 (0F000h) byte 的檔案
movdx, OFFSET Encrypted_Body
movbx, input_handle
int21h
movBody_Length, ax ;; 把檔案長度存起來
ret
endp
;;--------------------------------------------
;; 對讀取的內容編碼
;;--------------------------------------------
Encrypt_Body PROC near
movcx, Body_Length
movbx, OFFSET Encrypted_Body
encrypt_loop:
xorbyte ptr , cl
incbx
loop encrypt_loop
ret
endp
;;--------------------------------------------
;; 產生編碼後的 OUT.COM
;;--------------------------------------------
write_output_file PROC near
mov ax, body_length ;;
mov word ptr First_Jump+2, ax;; 製造 jmp Decoder 程式碼
mov word ptr Decoder+1, ax ;; 製造 mov cx, 檔案長度
;; ---------------------------------------------
;; 寫入 OUT.COM 的第一部份 [跳躍指令(到解碼段)]
;; ---------------------------------------------
mov cx, (OFFSET End_First_Jump) - (OFFSET First_Jump)
mov dx, OFFSET First_Jump
call Write_File
;; ---------------------------------------------
;; 寫入 OUT.COM 的第二部份 [編碼過後的原程式]
;; ---------------------------------------------
mov cx, Body_Length
mov dx, OFFSET Encrypted_Body
call Write_File
;; ---------------------------------------------
;; 寫入 OUT.COM 的第三部份 [解碼及返回]
;; ---------------------------------------------
mov cx, (OFFSET End_Decoder) - (OFFSET Decoder)
mov dx, OFFSET Decoder
call Write_File
ret
;;--------------
Write_File:
movah, 40h
movbx, output_handle
int21h
ret
endp
;;--------------------------------------------
;; 結束了
;;--------------------------------------------
End_all:
movbx, input_handle ;;
movah, 3eh ;;
int21h ;; 關閉 IN.COM
movbx, output_handle ;;
movah, 3eh ;;
int21h ;; 關閉 OUT.COM
movdx, OFFSET msg_Thanks ;;
movah, 09h ;;
int21h ;; 結束的訊息
movah, 4ch ;;
int21h ;; 程式結束
;;--------------------------------------------
;; 這裡放一些我們要用到的資料
;;--------------------------------------------
input_file DB 'IN.COM',0 ;;要編碼的檔案名稱
output_file DB 'OUT.COM',0 ;;編碼後的檔案名稱
input_handle DW 0 ;;IN.COM的檔案處理代碼
output_handleDW 0 ;;OUT.COM 的檔案處理代碼
body_length DW 0 ;;IN.COM 的檔案長度
;;------------------
;; 標題
;;------------------
msg_logo DB 0Ah, 0Dh
DB "---== My First and Simple .COM EncryptorV0.1 ==---",0ah, 0dh
DB "------------------------......----",0ah, 0dh
DB " ... Encrypts IN.COM into OUT.COM",0ah, 0dh
DB 0Ah, 0dh, '$'
;;------------------
;; 訊息: 錯誤發生
;;------------------
msg_error_open DB 'Error!', 0AH, 0DH, '$'
;;------------------
;; 訊息: 編碼成功
;;------------------
msg_Thanks DB 'File: IN.COM was encrypted to OUT.COM', 0AH, 0DH, '$'
;;--------------------------------------------
;; 這裡是 OUT.COM 要用到的程式碼
;;--------------------------------------------
;; ----------------------------------------
;; OUT.COM 的第一部份 [跳躍指令(到解碼段)]
;; ----------------------------------------
First_Jump:
pusha
db 0e9h ;; 我們會把這裡改成 OUT.COM 的 jmp Decoder
DW 0 ;;
End_First_Jump:
;; ---------------------------------
;; OUT.COM 的第三部份 [解碼及返回]
;; ---------------------------------
Decoder:
movcx, 0;; 我們會把這裡改成 OUT.COM 的 mov cx, 解碼長度
movsi, (OFFSET End_First_Jump) - (OFFSET First_Jump)
movdi, 100h
addsi, di
;; -----
;; 解碼
;; -----
Decrypt_Loop:
lodsb
xoral, cl
stosb
loop Decrypt_Loop
popa
push100h;; 返回位址為 IP=100h
ret
End_Decoder:
;; --------------------------------------
;; OUT.COM 的第二部份 [編碼過後的原程式]
;; --------------------------------------
Encrypted_Body:
end Start
>> ======== 在上一行結束 ==========
再來我們希望加上一些反追蹤技巧, 所以把上面程式 OUT.COM 的第三部份
[解碼及返回] 改成如下, 這樣一來如果我們就無法使用 Debug, Symdeb
甚至 Soft-ICE 的 LDR.EXE 載入 OUT.COM 來追蹤程式了.
至於原理, 我們就留待下回再分析了.
>> ======== 從下一行開始 ==========
;; ---------------------------------
;; OUT.COM 的第三部份 [解碼及返回]
;; ---------------------------------
Decoder:
movcx, 0;; 我們會把這裡改成 OUT.COM 的 mov cx, 解碼長度
movax, ds
andax, dx
movds, ax
moves, ax
movdi, si
addsi, (OFFSET End_First_Jump) - (OFFSET First_Jump)
;; -----
;; 解碼
;; -----
Decrypt_Loop:
lodsb
xoral, cl
stosb
loop Decrypt_Loop
popa
push100h;; 返回位址為 IP=100h
ret
End_Decoder:
>> ======== 在上一行結束 ==========
最後附上 CRYPTCOM.COM 有加入反追蹤技巧的版本. 您可以用下列的方法把
程式還原: (如果你沒有 TASM 的話.)
DEBUG.EXE < CRYPTCOM.ASC
>> ======== 從下一行開始 ==========
N CRYPTCOM.COM
E 0100 e8 12 00 e8 17 00 e8 2e 00 e8 3b 00 e8 4a 00 e8 54 00 e9 80 00 b4 09
E 0117 ba c5 01 cd 21 c3 b4 3d b0 00 ba b0 01 cd 21 72 04 a3 bf 01 c3 b4 09
E 012e ba 59 02 cd 21 b4 4c cd 21 b4 3c b9 00 00 ba b7 01 cd 21 72 e9 a3 c1
E 0145 01 c3 b4 3f b9 00 f0 ba a9 02 8b 1e bf 01 cd 21 a3 c3 01 c3 8b 0e c3
E 015c 01 bb a9 02 30 0f 43 e2 fb c3 a1 c3 01 a3 8c 02 a3 8f 02 b9 04 00 ba
E 0173 8a 02 e8 14 00 8b 0e c3 01 ba a9 02 e8 0a 00 b9 1b 00 ba 8e 02 e8 01
E 018a 00 c3 b4 40 8b 1e c1 01 cd 21 c3 8b 1e bf 01 b4 3e cd 21 8b 1e c1 01
E 01a1 b4 3e cd 21 ba 62 02 b4 09 cd 21 b4 4c cd 21 49 4e 2e 43 4f 4d 00 4f
E 01b8 55 54 2e 43 4f 4d 00 00 00 00 00 00 00 0a 0d 2d 2d 2d 3d 3d 20 4d 79
E 01cf 20 46 69 72 73 74 20 61 6e 64 20 53 69 6d 70 6c 65 20 2e 43 4f 4d 20
E 01e6 45 6e 63 72 79 70 74 6f 72 20 20 56 30 2e 31 20 3d 3d 2d 2d 2d 0a 0d
E 01fd 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d
E 0214 2d 2e 2e 2e 5b 5a 65 4e 69 58 20 6f 66 20 70 43 45 20 27 39 38 5d 2e
E 022b 2e 2e 2d 2d 2d 2d 0a 0d 20 2e 2e 2e 20 45 6e 63 72 79 70 74 73 20 49
E 0242 4e 2e 43 4f 4d 20 69 6e 74 6f 20 4f 55 54 2e 43 4f 4d 0a 0d 0a 0d 24
E 0259 45 72 72 6f 72 21 0a 0d 24 46 69 6c 65 3a 20 49 4e 2e 43 4f 4d 20 77
E 0270 61 73 20 65 6e 63 72 79 70 74 65 64 20 74 6f 20 4f 55 54 2e 43 4f 4d
E 0287 0a 0d 24 60 e9 00 00 b9 00 00 8c d8 23 c2 8e d8 8e c0 8b fe 83 c6 04
E 029e ac 32 c1 aa e2 fa 61 68 00 01 c3
RCX
01a9
w
q
>> ======== 在上一行結束 ==========
╒═════╤═══════════════════════════════
│[文件結束]│
╘═════╛
/ 楊旭峰
zenix@ms10.hinet.net 帮LZ顶了,支持原创技术 什么啊!!!没看懂.... 感谢zenix发布DOS下脱壳文章,加精华鼓励!
页:
[1]