baitang36 发表于 2018-9-3 10:02:35

fas文件格式研究

本帖最后由 baitang36 于 2022-7-5 08:27 编辑

根据后来的研究做一些修改,防止误导别人。上传了解码工具fas61.exe 2022-7-5
先看一个小程序 gys.lsp
;改任何实体的颜色 (c)SYZ 1995.3.18
(defun c:gys ()
(setq ss (ssget))
(setq tcol (getstring
      "\n输入新颜色(回车为白色,也可以改为其他颜色):<W> "
      )
)
(IF (= tcol "")
    (setq tstyle "W")
)
(command "change" ss "" "p" "c" tcol "")
)
为叙述方便,程序源码一律用10进制,fas文件内容显示一律用16进制。也就是winhex的显示模式。
在AutoCAD2008下编译成fas文件,内容如下:
Offset         0   1   2   3   4   5   67    8   9   A   BC   DEF
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 32 31 0D 0A 3134 20 24 14 00 00 00 00   12114 $   
00000030   35 00 0D 00 03 06 0C 0009 0B 00 35 01 0A 00 03   5          5   
00000040   06 09 00 03 09 00 09 0800 35 02 07 00 03 67 0B            5    g
00000050   00 00 00 09 06 00 06 0500 57 00 00 00 00 09 04            W      
00000060   00 51 01 03 00 01 00 0A03 0C 00 51 01 03 00 01    Q         Q   
00000070   00 0A 09 08 00 51 01 0300 01 00 0A 09 02 00 51      Q         Q
00000080   01 03 00 01 00 0A 09 0100 51 01 03 00 01 00 0A            Q      
00000090   03 09 00 51 01 03 00 0100 0A 09 08 00 51 01 03      Q         Q
000000A0   00 01 00 16 24 0D 0A 3235 30 20 35 20 24 32 E2       $250 5 $2?
000000B0   25 F1 1E D6 E4 BE 6B 1B64 06 12 11 62 2F 3C 46   %?咒緆 d   b/<F
000000C0   58 4C 4F 4F 55 9D 40 964A F0 1E BF A7 B6 0D 68   XLOOU @朖?咖?h
000000D0   0E 07 12 46 15 00 11 071F 0D 01 50 31 CA 5F C9      F       P1蔩?
000000E0   1D F1 1E B1 E6 8C 4B 313E 06 12 37 42 22 75 74    ?辨孠1>7B"ut
000000F0   36 6E 66 06 31 F8 73 E224 F6 1E 87 8C ED 24 56   6nf 1鴖??噷?V
00000100   38 5C 46 14 40 1A 5D 421B 0D 5E 63 31 F9 26 B4   8\F @ ]B^c1??
00000110   7F CD 1E E4 B1 8D 4A 315D 5C 46 04 5B 0F 11 40    ?浔 J1]\F [@
00000120   5E 59 58 36 63 B1 68 A424 F0 4B E5 E4 A3 4A 3B   ^YX6c県?餕邃;
00000130   97 E3 DA AC C4 81 C0 D2D2 A6 23 D9 E9 4B 93 2D   椼诂?酪姚#匍K?
00000140   8E 40 C9 2D 4F A0 98 83E2 CE C0 93 AC 87 DF AD   嶡?O牁冣卫摤囘?
00000150   DD E9 C0 99 E0 2D EF 480D CA 22 B3 DA AC 11 62   蓍罊?颒 ?弛?b
00000160   0E 07 41 14 53 06 45 071B 51 0B 62 72 F8 26 ED   A S EQ br??
00000170   24 FA 42 E4 E4 BE 4A 6A1E 3D 55 1E 47 43 11 3D   $鶥滗綣j =U GC =
00000180   1A 4E 0F 62 30 F8 3A F725 F0 1E E4 ED 8F 4A 3B    N b0???漤 J;
00000190   0A 07 12 47 14 4A 15 071D 0F 0B 6B 33 F8 13 E2      G J   k3??
000001A0   25 F0 1F EE ED 8E 4A 2718 C3 E5 06 22 D2 CC 28   %?铐嶫' 缅 "姨(
000001B0   CC 40 0A 3B 66 61 73 3420 63 72 75 6E 63 68 0A   藹 ;fas4 crunch
000001C0   3B 24 3B 41 39 2F 33 2F31 38                              ;$;A9/3/18

经过测试,注释部分对编译后的文件无任何影响,因此编译后注释会丢失。

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!
这两行是fas文件的文件头,任何程序编译的fas文件都不变,FAS4-FILE 可以作为判断是否为fas文件
的依据。
00000020   0D 0A 31 32 31 0D 0A 3134 20 24 14 00 00 00 00   12114 $   
这一行有两个数字,121 和14,121是第一段的长度,14是函数模块的符号个数。
表示从地址 2B开始到地址A4,共有121个字节。
                                                                  14 00 00 00 00   
00000030   35 00 0D 00 03 06 0C 0009 0B 00 35 01 0A 00 03   5          5   
00000040   06 09 00 03 09 00 09 0800 35 02 07 00 03 67 0B            5    g
00000050   00 00 00 09 06 00 06 0500 57 00 00 00 00 09 04            W      
00000060   00 51 01 03 00 01 00 0A03 0C 00 51 01 03 00 01    Q         Q   
00000070   00 0A 09 08 00 51 01 0300 01 00 0A 09 02 00 51      Q         Q
00000080   01 03 00 01 00 0A 09 0100 51 01 03 00 01 00 0A            Q      
00000090   03 09 00 51 01 03 00 0100 0A 09 08 00 51 01 03      Q         Q
000000A0   00 01 00 16 24
第二段的头从地址A5开始,长度是250,符号个数是5
第二段的内容开始地址是AE,结束地址是1A7,共有250个字节
                                                      32 E2      
000000B0   25 F1 1E D6 E4 BE 6B 1B64 06 12 11 62 2F 3C 46   %?咒緆 d   b/<F
000000C0   58 4C 4F 4F 55 9D 40 964A F0 1E BF A7 B6 0D 68   XLOOU @朖?咖?h
000000D0   0E 07 12 46 15 00 11 071F 0D 01 50 31 CA 5F C9      F       P1蔩?
000000E0   1D F1 1E B1 E6 8C 4B 313E 06 12 37 42 22 75 74    ?辨孠1>7B"ut
000000F0   36 6E 66 06 31 F8 73 E224 F6 1E 87 8C ED 24 56   6nf 1鴖??噷?V
00000100   38 5C 46 14 40 1A 5D 421B 0D 5E 63 31 F9 26 B4   8\F @ ]B^c1??
00000110   7F CD 1E E4 B1 8D 4A 315D 5C 46 04 5B 0F 11 40    ?浔 J1]\F [@
00000120   5E 59 58 36 63 B1 68 A424 F0 4B E5 E4 A3 4A 3B   ^YX6c県?餕邃;
00000130   97 E3 DA AC C4 81 C0 D2D2 A6 23 D9 E9 4B 93 2D   椼诂?酪姚#匍K?
00000140   8E 40 C9 2D 4F A0 98 83E2 CE C0 93 AC 87 DF AD   嶡?O牁冣卫摤囘?
00000150   DD E9 C0 99 E0 2D EF 480D CA 22 B3 DA AC 11 62   蓍罊?颒 ?弛?b
00000160   0E 07 41 14 53 06 45 071B 51 0B 62 72 F8 26 ED   A S EQ br??
00000170   24 FA 42 E4 E4 BE 4A 6A1E 3D 55 1E 47 43 11 3D   $鶥滗綣j =U GC =
00000180   1A 4E 0F 62 30 F8 3A F725 F0 1E E4 ED 8F 4A 3B    N b0???漤 J;
00000190   0A 07 12 47 14 4A 15 071D 0F 0B 6B 33 F8 13 E2      G J   k3??
000001A0   25 F0 1F EE ED 8E 4A 27
第三段的开头地址是1A8,是字节18,这个是16进制,也就是十进制的24,说明第三段的长度
是24个字节。
                                                         C3 E5 06 22 D2 CC 28   
000001B0   CC 40 0A 3B 66 61 73 3420 63 72 75 6E 63 68 0A   藹 ;fas4 crunch
000001C0   3B
第四段是从地址1C2开始,内容是:
000001C0   3B 24 3B 41 39 2F 33 2F31 38                     ;A9/3/18
是文件的编译月、日、年,A9表示是9月,3是日,18是年,也就是今天。


基本可以确定的是:
第一段跟是否定义了函数有关,没有defun的程序没有第一段。
第二段所有fas文件都有,是加密的。
第三段是解密第二段用的key,是随机变化的。但每个key后半部分都是“fas4 crunch”
第四段是编译日期,这是确定的。
第二段内容的加密算法非常简单,只是每个字节两次xor运算。
解密后可以看到被加密的字符串。
第二段内容的解密算法很简单,用汇编语言表示是这样的:
lodsb ;取第二段内容一个字节
mov bl,byte ptr ;取key第一个字节
mov bh,byte ptr ;取key第二个字节   
xor bl,bh               ;异或运算
xor al,bl               ;异或运算
stosb                   ;解密后的明文字节

编了一个小程序,用来解密这部分内容,用汇编语言写的,程序很小,也不加密了。
感兴趣的可以od看看,汇编语言写的程序和看源码是一样的。
解密后的fas文件是这样的;
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 32 31 0D 0A 3134 20 24 14 00 00 00 00   12114 $   
00000030   35 00 0D 00 03 06 0C 0009 0B 00 35 01 0A 00 03   5          5   
00000040   06 09 00 03 09 00 09 0800 35 02 07 00 03 67 0B            5    g
00000050   00 00 00 09 06 00 06 0500 57 00 00 00 00 09 04            W      
00000060   00 51 01 03 00 01 00 0A03 0C 00 51 01 03 00 01    Q         Q   
00000070   00 0A 09 08 00 51 01 0300 01 00 0A 09 02 00 51      Q         Q
00000080   01 03 00 01 00 0A 09 0100 51 01 03 00 01 00 0A            Q      
00000090   03 09 00 51 01 03 00 0100 0A 09 08 00 51 01 03      Q         Q
000000A0   00 01 00 16 24 0D 0A 3235 30 20 35 20 24 14 01       $250 5 $
000000B0   01 01 00 32 00 32 21 2A39 01 00 56 76 6C 2D 41      2 2!*9Vvl-A
000000C0   43 41 44 2D 64 65 66 756E 00 00 5B 43 3A 47 59   CAD-defun[C:GY
000000D0   53 00 00 01 01 43 00 0004 00 0A 32 00 32 79 2A   S    C   2 2y*
000000E0   39 01 00 55 02 00 01 0063 01 00 70 56 61 64 73   9U    cpVads
000000F0   2D 63 6D 64 00 00 55 0100 06 00 63 68 61 6E 67   -cmdU    chang
00000100   65 5B 54 53 54 59 4C 4500 00 55 01 00 01 00 57   e[TSTYLEU    W
00000110   5B 3D 00 00 55 01 00 0000 5B 54 43 4F 4C 00 47   [=U    [TCOL G
00000120   45 54 53 54 52 49 4E 4700 00 55 01 00 2F 00 0A   ETSTRINGU/
00000130   CA E4 C8 EB D0 C2 D1 D5C9 AB 28 BB D8 B3 B5 CE   输入新颜色(回车?

00000140   AA B0 D7 C9 AB 2C D2 B2BF C9 D2 D4 B8 C4 CE AA   咨?也可以改为
00000150   C6 E4 CB FB D1 D5 C9 AB29 3A 3C 57 3E 20 5B 53   其他颜色):<W> [S
00000160   53 00 53 53 47 45 54 0000 5C 00 00 43 00 00 0E   S SSGET\C   
00000170   00 0A 5C 00 00 32 00 5B43 3A 47 59 53 00 00 3A   \2 [C:GYS:
00000180   01 43 04 00 01 00 1C 1401 00 00 00 09 03 00 0A    C            
00000190   57 00 00 00 00 09 04 0006 02 00 09 02 00 35 01   W             5
000001A0   01 00 01 0A 09 02 00 1618 C3 E5 06 22 D2 CC 28            缅 "姨(
000001B0   CC 40 0A 3B 66 61 73 3420 63 72 75 6E 63 68 0A   藹 ;fas4 crunch
000001C0   3B 24 3B 41 39 2F 33 2F31 38                     ;$;A9/3/18
可以看到字符串已经还原了。
fas2.exe的作用是把当前目录下的fas1.fas解密,生成new_fas1.fas
用法是把你的fas文件复制到当前目录下,改名为fas1.fas,然后双击fas2.exe.


研究了几天,成果向大家汇报一下,欢迎感兴趣的朋友和我一起研究,我的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,看来变量的存放顺序是倒着的,先用的序号大,后用的序号小。
现在开始研究字符串在fas文件中的存放
先看小程序:
(princ "555555555555")
(princ "333333333333")
(princ "222222222222")
(princ "11111111111")
这小程序没有定义函数,只是显示几个字符串。
先用到的字符串放到后面,后用到的在前面。
可能大家会感到奇怪,为什么没有“44444444”?
是给princ留着,第四个字符串就是princ,命令也是字符串。
看看编译解码后的fas,是这样的:
Offset          0   1    2   3   4    5   6   7   8   9    AB   C   D   E   F
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 0D 0A 31 20 2420 24 0D 0A 31 35 32 20   11 $ $152
00000030   37 20 24 14 01 01 01 0032 00 32 2D 2A 39 01 00   7 $   2 2-*9
00000040   55 03 00 0B 00 31 31 3131 31 31 31 31 31 31 31   U    11111111111
00000050   0C 00 32 32 32 32 32 3232 32 32 32 32 32 0C 00   222222222222
00000060   33 33 33 33 33 33 33 3333 33 33 33 5B 50 52 49   333333333333[PRI
00000070   4E 43 00 00 55 01 00 0C00 35 35 35 35 35 35 35   NCU    5555555
00000080   35 35 35 35 35 01 01 4300 00 07 00 0A 01 5C 00   55555C      \
00000090   00 43 00 00 01 00 0A 0143 07 00 00 00 1C 14 01    C      C      
000000A0   00 00 00 09 06 00 0A 0905 00 35 01 04 00 03 0A             5   
000000B0   09 03 00 35 01 04 00 030A 09 02 00 35 01 04 00      5      5   
000000C0   03 0A 09 01 00 35 01 0400 03 16 18 00 94 F7 8D      5       旝
000000D0   32 53 23 E3 E9 0A 3B 6661 73 34 20 63 72 75 6E   2S#汩 ;fas4 crun
000000E0   63 68 0A 3B 24 3B 41 392F 38 2F 31 38            ch ;$;A9/8/18
确实按我们设想的顺序排列了,这说明我们的猜想是正确的。
字符串的顺序就是先用到的字符串放到后面,后用到的排在前面。
根据上一次我们找到的规律,程序段是以14开头,以16结尾。从字符串后面开始找,程序段
开始的地址是9E,结束地址是CA。
程序内容是14 01 00 00 00
09 06 00 0A
09 05 00 35 01 04 00 03 0A         
09 03 00 35 01 04 00 030A
09 02 00 35 01 04 00 03 0A
09 01 00 35 01 04 00 03 16
掐头去尾,找四个模样差不多的句子。我们大胆猜想一下:
0905 00 35 01 04 00 03是(princ "555555555555")
09 03 00 35 01 04 00 03 是(princ "333333333333")
09 02 00 35 01 04 00 03是(princ "222222222222")
09 01 00 35 01 04 00 03是(princ "11111111111")
经过修改内容,重新编译解码,证明这猜想是正确的。
这四个句子共同的特点就是:
09 xx 00 35 01 04 00 03
xx正好是我们的字符串顺序,当然,是倒序。01 00 表示0001,就是字符串"11111111111"
04 00表示0004,是princ,和我们预想的一样。
程序段的头是14 01 00 00 00,和以前defun里面的头不太一样,那个是14 00,这里是14 01
09 06 00 0A不知道是什么意思,09和0A应该是指令,06 00像是字符串编号0006,但我们只有5个字符串,怎么会出来第6号?
09 01 00 35 01 04 00 03是(princ "11111111111")从这一句可以看出09这个指令是根据编号01 00取得字符串"11111111111"
35 01这个是执行04 00号命令,也就是princ。
前边几句09 和0A是成对出现的,最后一句没有0A,因此0A可能是另起一行的意思吧?
那03是什么意思?暂且把它当成“)”,以后再研究。
研究到现在,似乎遇到瓶颈了。
现在可以猜测出很多指令,可以反编译回去,如 09 01 00 06 0200这样的就是(setq xxx yyy)
但如果用程序来反编译,就会遇到大量的未知指令。
程序是没法自己去猜测的。通过试验来确定某个指令编译后的样子也不太靠谱,因为无法做到写出的源代码能够编译出所有的指令,并且这样做效率也太低。
那怎么办?只能通过研究acad.exe对fas文件的调用、处理过程了。
授人以鱼不如授人以渔,把我的方法写出来,感兴趣者一起研究吧。
我的研究方法如下:
运行AutoCAD2008,打开od,附加acad.exe进程,设置打开文件断点bp CreateFileA,然后设置读文件断点bp ReadFile,按F9让CAD正常运行,然后(load “ttt.fas”)加载ttt.fas,程序运行到CreateFileA断点停下,看一下,确实是打开ttt.fas,再按F9,程序停在readfile断点,可以看到是读取1000个字节到缓冲区。
记下缓冲区地址,按Ctrl+F9执行到返回,看一下缓冲区的内容,确实是文件ttt.fas的内容。然后在缓冲区的解码部分(一般是14 01 01 01 00)设置硬件访问断点,程序读取这个位置会停下,发现是调用了memcopy函数,程序VL会把这段内容复制到另一个地址,在这个地址设置硬件访问断点,程序运行到操作这段代码时暂停。
终于找到关键的地方了。这里的程序反汇编是这样的
mov al,byte ptr ds:;读取一个字节
add esi,ebp                        ;计数器加一
movzx ecx,al                      ;字符放到cl中
add ecx,-0x1                      ;字符数值减一
cmp ecx,0x69                     ;比较字符的值是否大于6AH
ja short vl.0C228932         ;大于6A是非法字符,转错误处理
jmp dword ptr ds: ;合法指令,转到对应地址去处理
由这段程序可以看出,fas指令的合法字符是01-6Ah,每个指令对应一段处理程序。程序的入口地址存放在 处的一张表中,这里的ecx是指令减一,如指令09 处理程序的入口地址就是【(9-1)*4+0xc22a38h】,这是我跟踪时的地址,不同的电脑可能是不同的。
研究这张表中的所有子程序,就可以知道fas的每一个指令是如何处理的。这样就可以充分地了解fas的106个指令。


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




lisperado 发表于 2018-10-28 10:31:11

回帖是美德。。。
听说ZWCAD也搞编译*.ZEL格式,而且也支持 *.FAS & *.VLX?
反而觉得vl.dll被ZW程序员反编译的可能性更大?

下一站ZEL。。。
版主加油加油

NetBee 发表于 2018-10-5 23:40:08

本帖最后由 NetBee 于 2018-10-5 23:43 编辑

VL在编译时,会提示是标准模式还是优化链接模式,若是标准模式的话,变量名没有改变的,可以完全逆回源代码。若是优化模式的话,变量名变了,增加了代码的可读难度。
函数代码表是可以通过编程来找到代码表的。
当然若没有这么深的功底,就用笨办法吧,将所有命令列出,编译后看代码。


yxp 发表于 2018-9-8 20:09:39

本帖最后由 yxp 于 2018-9-8 20:13 编辑

baitang36 发表于 2018-9-8 19:57
是的,能运行可以玩破解,修改几个字节就跳过注册。
严格的说,世界上没有绝对安全的代码,只要你决心闯入源码,因为 arx 都可以被破译。
世界上的软件大公司都放弃了软件的高强度加密,比如微软,桌子,甲骨文等。
他们选择用法律武器来捍卫自己的知识产权,在欧美打个官司花的钱,远远低于软件的开发投入。
所以这是一个成本问题,而不是技术问题。

但是在中国。。。。。有很多像苏州思杰马克丁这样不要脸的软件公司。

baitang36 发表于 2018-9-3 10:09:03

这是我在明经发的第一个主题帖子,虽然注册很长时间了,只是在看别人的帖子。
坛内大虾很多,用这帖子抛砖引玉,望不吝赐教。

依然小小鸟 发表于 2018-9-3 10:40:28

baitang36 发表于 2018-9-3 10:09
这是我在明经发的第一个主题帖子,虽然注册很长时间了,只是在看别人的帖子。
坛内大虾很多,用这帖子抛砖 ...

支持一下{:1_1:}{:1_1:}

baitang36 发表于 2018-9-3 11:05:48

本帖最后由 baitang36 于 2018-9-3 11:25 编辑

已编辑合并到一楼:-)

yoyrtweq 发表于 2018-9-3 11:42:13

文件太大,无法处理

qxwangtao 发表于 2018-9-3 12:44:21

这个有什么用呢

baitang36 发表于 2018-9-3 13:43:32

本帖最后由 baitang36 于 2018-9-12 21:38 编辑

qxwangtao 发表于 2018-9-3 12:44
这个有什么用呢
到了这一步,相当于掀开了裙子的一角。
能看到里面的字符串了。
对于有些明着保存的密码,你可以知道了。

baitang36 发表于 2018-9-3 13:44:47

yoyrtweq 发表于 2018-9-3 11:42
文件太大,无法处理

你的文件很大吗?我实验过大小60k的,没问题。

yoyrtweq 发表于 2018-9-3 13:47:53

baitang36 发表于 2018-9-3 13:44
你的文件很大吗?我实验过大小60k的,没问题。

586K而且 FAS如何编译成LISP文件是个问题

baitang36 发表于 2018-9-3 14:00:21

yoyrtweq 发表于 2018-9-3 13:47
586K而且 FAS如何编译成LISP文件是个问题
奥,这么大啊。我还没见过如此大的fas呢,如果不保密的话,发给我看看?5520971@qq.com
慢慢来吧,没别的办法。
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: fas文件格式研究