baitang36
发表于 2018-9-4 21:57:33
本帖最后由 baitang36 于 2018-9-12 21:39 编辑
zixuan203344 发表于 2018-9-4 17:34
52破解上应该是复制的你的帖子吧
那是我的马甲,备份
ghgh0130
发表于 2018-9-5 08:15:20
彳余
发表于 2018-9-6 07:34:11
破冰之旅!支持作者!
yxp
发表于 2018-9-7 01:10:47
本帖最后由 yxp 于 2018-9-8 19:59 编辑
按 baitang36 的思路,我试了一下用 lisp 也可以解密 fas,不用汇编程序,降低研究门槛。有兴趣的来和baitang36一起把 fas 文件逆向工程了
在cad里加载运行 unfas
请到32楼下载新版,fas的解密lisp运行需要dwx环境
记事本打开fas文件
;;fas 文件解密by yxp_xa 2018年9月7日
;;按 baitang36 的思路将 fas 文件解密,似乎作用不大,和 lisp 源码相比还有一些差距
;;解密后的文件以二进制存储,需要用编辑器的 HEX 模式查看
(vl-load-com)
(defun c:unfas()
(or fasPath (setq fasPath ""))
(setq ps (getfiled "打开 .fas 文件" fasPath "fas" 0))
(if ps (progn
(or dwx (setq dwx (vlax-create-object "DynamicWrapperX")))
(princ "\n正在载入fas文件...")
(setq fasSize (Load_Fasfile_mem (setq fasPath ps)))
(princ (strcat "成功载入 " (itoa fasSize) " 字节"))
(princ "\n正在分析...")
(Fas_Section_data)
(princ "\n正在解密...")
(Decry_Fas_data)
(princ "\n正在导出解密fas文件...")
(Save_Fas_text)
))
(princ)
)
;;保存 fas 解密后的代码,仅第二段
(defun Save_Fas_text( / n)
(setq file (strcat (vl-filename-directory fasPath) "\\"
(vl-filename-base fasPath) "_bak.bin"))
(setq n (length DecList) o 0)
(setq fp (vlax-invoke dwx 'MemAlloc n 1))
(foreach x DecList
(vlax-invoke dwx 'NumPut x fP o "b")
(setq o (1+ o))
)
(vlax-invoke dwx 'Register "kernel32" "CreateFileW" "i=wllplll" "r=l")
(vlax-invoke dwx 'Register "kernel32" "WriteFile" "i=pplpl" "r=l")
(vlax-invoke dwx 'Register "kernel32" "CloseHandle" "i=p" "r=l")
(setq FileID (vlax-invoke dwx 'CreateFileW file 1073741824 1 0 4 128 0))
(setq FineNumber (vlax-invoke dwx 'MemAlloc 4 1))
(vlax-invoke dwx 'WriteFile FileID fp n FineNumber 0)
(vlax-invoke dwx 'CloseHandle FileID)
(vlax-invoke dwx 'NumGet FineNumber)
(princ (strcat "\n解密文件已保存到: " file))
)
;;fas文件解码,虽然dwx也可以运行汇编代码,但此处没有必要
(defun Decry_Fas_data()
(setq seconDecList (mapcar 'Hex2Dec (Txt_Split secondHex " ")))
(setq n 1 key1 (car fasKey) key2 (cadr fasKey) DecList nil)
(setq kmax (- (length fasKey) 2)) ;;扣掉末尾字符串
(foreach x seconDecList
(setq DecList (cons (Boole 6 x key1 key2) DecList)
key1 key2
n (if (> n kmax) 0 (1+ n)) ;;key 指针越位归零
key2 (nth n fasKey))
)
(setq DecList (reverse DecList)) ;;解密后的fas,10进制
(setq HexList (mapcar 'Dec2Hex DecList)) ;;解密后的fas,16进制
)
;;fas数据分析与分段
(defun Fas_Section_data()
;;fas头文件
;;读入fas字符串,遇到 00 自动结束
(setq headFasText (vlax-invoke dwx 'StrGet fasPoint "s"))
(setq headList (Txt_Split headFasText "\r\n"))
(setq txt (vl-string-trim " " (cadr headList)))
(princ (strcat "\n头文件: " txt))
;;fas第一段
(setq firstAddr (+ (vl-string-search "$" headFasText) 1))
(setq firstSize (atoi (caddr headList))) ;;得到第一段字节大小:121
(setq firstNum (atoi (last headList))) ;;得到第一段变量个数: 14
;;第一段hex编码
(setq firstHex (vlax-invoke DWX 'MemRead (+ fasPoint firstAddr) firstSize 1))
(princ (strcat "\n第一段,地址:" (Dec2Hex firstAddr) " 大小:" (itoa firstSize)))
;;fas第二段
(setq secondAddr (+ firstAddr firstSize 1))
(setq ptxt (vlax-invoke dwx 'MemAlloc 16 1));;分配16个字节接收15个字符
(vlax-invoke dwx 'MemCopy (+ fasPoint secondAddr) ptxt 15)
(setq txt (vlax-invoke dwx 'StrGet ptxt "s"))
(setq posiTxt (vl-string-search "$" txt)) ;;第二段的说明文字
(setq txt (vl-string-left-trim "\r\n" txt))
(setq Ltxt (Txt_Split txt " "))
(setq secondSize (atoi (car Ltxt))) ;;第二段字节大小
(setq secondNum (atoi (cadr Ltxt)));;第二段变量个数
(setq secondAddr (+ secondAddr posiTxt 1))
;;第二段hex编码
(setq secondHex (vlax-invoke DWX 'MemRead (+ fasPoint secondAddr) secondSize 1))
(princ (strcat "\n第二段,地址:" (Dec2Hex secondAddr) " 大小:" (itoa secondSize)))
;;fas第三段 提取 fasKey
(setq thirdAddr (+ secondAddr secondSize))
(setq thirdSize (vlax-invoke dwx 'NumGet fasPoint thirdAddr "b")) ;;第三段字节大小
;;第三段hex编码
(setq thirdHex (vlax-invoke DWX 'MemRead (+ fasPoint thirdAddr 1) thirdSize 1))
(setq fasKey (mapcar 'Hex2Dec (Txt_Split thirdHex " ")))
(princ (strcat "\n第三段,地址:" (Dec2Hex thirdAddr) " 大小:" (itoa thirdSize)))
;;fas第四段
(setq fourthAddr (+ thirdAddr thirdSize 1))
(setq fourthTxt (vlax-invoke dwx 'StrGet (+ fourthAddr fasPoint 1) "s"))
(setq fourthTxt (vl-string-left-trim ";" fourthTxt))
(princ (strcat "\n第四段,地址:" (Dec2Hex fourthAddr) " 编译日期:" fourthTxt))
)
;;读入fas文件至内存
;;成功返回载入文件的大小,失败则返回nil,文件指针以全局变量fasPoint返回
(defun Load_Fasfile_mem(file / FileID tf FileSize FineNumber fsize)
(if (setq tf (findfile file))(progn
(vlax-invoke dwx 'Register "kernel32" "CreateFileW" "i=wllplll" "r=l")
(vlax-invoke dwx 'Register "kernel32" "ReadFile" "i=pplpl" "r=l")
(vlax-invoke dwx 'Register "kernel32" "CloseHandle" "i=p" "r=l")
(setq FileID (vlax-invoke dwx 'CreateFileW tf 1 1 0 3 128 0))
(setq FileSize (vl-file-size tf))
(setq fasPoint (vlax-invoke dwx 'MemAlloc FileSize 1))
(setq FineNumber (vlax-invoke dwx 'MemAlloc 4 1))
(vlax-invoke dwx 'ReadFile FileID fasPoint FileSize FineNumber 0)
(vlax-invoke dwx 'CloseHandle FileID)
(setq fsize (vlax-invoke dwx 'NumGet FineNumber))
))
)
;;字符分割
(defun Txt_Split (str sep / Pos1 Pos2 NStr)
(setq Pos2 1)
(while (setq Pos1 (vl-string-search sep str Pos1))
(setq NStr (cons (substr str Pos2
(if (= Pos2 1) Pos1 (- (1+ Pos1) Pos2))) NStr)
Pos2 (1+ (+ (strlen sep) Pos1))
Pos1 (+ Pos1 (strlen sep)))
)
(reverse (cons (substr str Pos2) NStr))
)
;;十六进制转10进制
(defun Hex2Dec(h)
(setq hex (strcase h) n (strlen hex) m 0 sum 0
con '(("0" 0)("1" 1)("2" 2)("3" 3)("4" 4)("5" 5)("6" 6)("7" 7)("8" 8)
("9" 9)("A" 10)("B" 11)("C" 12)("D" 13)("E" 14)("F" 15)))
(while (> n 0)
(setq sum (+ (* (cadr (assoc (substr hex n 1) con))(expt 16 m)) sum)
m (1+ m) n (1- n)
)) sum
)
程序运行需要 dwx 的支持 (for x64),请自行下载并注册 dll
水吉空
发表于 2018-9-7 16:35:43
有一段时间没上论坛,没想到又有大佬出现,厉害了,学您学习
kozmosovia
发表于 2018-9-7 19:14:58
14不是什么长度,好像是这个段的变量个数
baitang36
发表于 2018-9-8 08:28:15
本帖最后由 baitang36 于 2018-9-8 08:38 编辑
研究了几天,成果向大家汇报一下,欢迎感兴趣的朋友和我一起研究,我的qq5520971。
乐趣存在于过程中,也许最终完成的时候也就没什么兴趣了。这就像猜谜语,谜底出来的时候也就索然无味了。
先看下面这个小程序:
(defun c:ddd ()
(setq a 187)
(setq b 170)
(setq c (+ a b))
(princ c)
)
(defun c:eee ()
(setq a 188)
(setq b 171)
(setq c (+ a b))
(princ c)
)
(defun c:fff ()
(setq dd 189)
(setq ee 172)
(setq ff (+ a b))
(princ ff)
)
大家可能觉得数字挺奇怪,为什么用170 171 172 之类的数字?
十进制的170是16进制的AA,,171是AB,172是AC,187是BB,188是BC,
用这些特殊数字的目的是为了在编译后的文件中容易找到:-)。
编译解码后的文件是这样的,当然是用16进制显示的。
Offset 01234567 89ABCDEF
00000000 0D 0A 20 46 41 53 34 2D46 49 4C 45 20 3B 20 44 FAS4-FILE ; D
00000010 6F 20 6E 6F 74 20 63 6861 6E 67 65 20 69 74 21 o not change it!
00000020 0D 0A 31 33 32 0D 0A 3920 24 14 00 00 00 00 33 1329 $ 3
00000030 BB 00 00 00 06 08 00 33AA 00 00 00 06 07 00 03 ? 3?
00000040 08 00 03 07 00 35 02 0600 03 06 05 00 03 05 00 5
00000050 35 01 04 00 03 16 14 0000 00 00 33 BC 00 00 00 5 3?
00000060 06 08 00 33 AB 00 00 0006 07 00 03 08 00 03 07 3?
00000070 00 35 02 06 00 03 06 0500 03 05 00 35 01 04 00 5 5
00000080 03 16 14 00 00 00 00 33BD 00 00 00 06 03 00 33 3? 3
00000090 AC 00 00 00 06 02 00 0308 00 03 07 00 35 02 06 ? 5
000000A0 00 03 06 01 00 03 01 0035 01 04 00 03 16 24 0D 5 $
000000B0 0A 32 34 34 20 39 20 2414 01 01 01 00 32 00 32 244 9 $ 2 2
000000C0 51 2A 39 01 00 5B 43 3A46 46 46 00 43 3A 45 45 Q*9[C:FFF C:EE
000000D0 45 00 00 56 76 6C 2D 4143 41 44 2D 64 65 66 75 EVvl-ACAD-defu
000000E0 6E 00 00 5B 43 3A 44 4444 00 00 01 01 43 00 00 n[C:DDD C
000000F0 06 00 0A 32 58 33 84 0000 00 2A 32 2C 32 58 2A 2X3?*2,2X*
00000100 32 00 32 2C 2A 39 03 005B 46 46 00 45 45 00 44 2 2,*9[FF EE D
00000110 44 00 50 52 49 4E 43 0043 00 2B 00 42 00 41 00 D PRINC C + B A
00000120 00 5C 00 00 43 00 00 0900 0A 5C 00 00 32 58 5B \C \2X[
00000130 43 3A 46 46 46 00 00 3A5C 00 00 32 2C 5B 43 3A C:FFF:\2,[C:
00000140 45 45 45 00 00 3A 5C 0000 32 00 5B 43 3A 44 44 EEE:\2 [C:DD
00000150 44 00 00 3A 01 43 06 0003 00 1C 14 01 00 00 00 D: C
00000160 09 05 00 0A 57 00 00 0000 09 08 00 06 04 00 09 W
00000170 04 00 35 01 03 00 01 0A09 04 00 0A 57 00 00 00 5 W
00000180 00 09 07 00 06 02 00 0902 00 35 01 03 00 01 0A 5
00000190 09 02 00 0A 57 00 00 0000 09 06 00 06 01 00 09 W
000001A0 01 00 35 01 03 00 01 0A09 01 00 16 15 00 19 34 5 4
000001B0 32 3F CC 0A 3B 66 61 7334 20 63 72 75 6E 63 68 2??;fas4 crunch
000001C0 0A 3B 24 3B 41 39 2F 342F 31 38 ;$;A9/4/18
经过多次试验,现在可以弄明白的是,从地址2A开始是程序代码,它是没加密的,也就是
这部分代码:
Offset 012 3 4 5 67 8 9 A BC D E F
00000020 14 00 00 00 00 33 1329 $ 3
00000030 BB 00 00 00 06 08 00 33AA 00 00 00 06 07 00 03 ? 3?
00000040 08 00 03 07 00 35 02 0600 03 06 05 00 03 05 00 5
00000050 35 01 04 00 03 16 14 0000 00 00 33 BC 00 00 00 5 3?
00000060 06 08 00 33 AB 00 00 0006 07 00 03 08 00 03 07 3?
00000070 00 35 02 06 00 03 06 0500 03 05 00 35 01 04 00 5 5
00000080 03 16 14 00 00 00 00 33BD 00 00 00 06 03 00 33 3? 3
00000090 AC 00 00 00 06 02 00 0308 00 03 07 00 35 02 06 ? 5
000000A0 00 03 06 01 00 03 01 0035 01 04 00 03 16
这里的数据14 00 00 00 00 33 BB 00 00 00 06 08 00 33AA 00 00 00 06 07 00
03 08 00 03 07 00 35 02 0600 03 06 05 00 03 05 0035 01 04 00 03 16
就是程序代码:
( (setq a 187)
(setq b 170)
(setq c (+ a b))
(princ c)
)
14是开头,16是结尾,当然,都是16进制。
33 BB 00 00 00 06 08 00这一句就是(setq a 187) ,十进制的187就是16进制的BB
BB 00 00 00占用4个字节,说明是32位整数。
33应该有某种意义,暂不管它。
06应该是相当于命令setq
08 00占用两个字节,数字在内存中的存放时低位在前,高位在后的。08 00也就是数字8
在这里应该是表示变量a,它是第8号?
按以上规律再来看下一句
33AA 00 00 00 06 07 00就是(setq b 170)
AA 00 00 00是数字170,07 00是7号变量?
a是8,b是7,看来变量的存放顺序是倒着的,先用的序号大,后用的序号小。
现在遇到的问题是,这个序号是怎么来的?等我研究后,再跟大家分享。
等我好消息,今天就到这里。
补充一下,因为资料特别缺乏,文中观点都是猜测加试验验证,有可能是错的,欢迎大家提出经过验证的相反意见。
baitang36
发表于 2018-9-8 08:49:37
本帖最后由 baitang36 于 2018-9-8 12:20 编辑
yxp 发表于 2018-9-7 01:10
地址 0x00 - 0x21:从0D0A 开始到 0D0A结束,共计34字节。
0D 0A 的十进制就是 13 10,转换成ASCII码就是 ...
14是某段程序的开头,16是结尾 这里是字符串个数+1?
baitang36
发表于 2018-9-8 08:53:24
fl202 发表于 2018-9-4 11:17
厉害!
强贴占位。
等将来再回答这个问题,现在刚开始研究
ymcui
发表于 2018-9-8 08:57:02
利害,先做个标记.