[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
回复 13# email10t


用 debug 跑了一下,看明白了构思,但不懂 DB      6A 是起什么作用的...记得之前跟踪 Herbert Kleebauer 的方案也有多处这样的字节,一直不知道是用来干嘛的

运行后的反汇编结果
  1. SUB     AL,35
  2. PUSH    AX
  3. DB      6A
  4. AND     [DI+5F],BX
  5. DB      6A
  6. PUSH    SP
  7. POP     AX
  8. SUB     [BP+DI+21],AL
  9. INT     21
复制代码

TOP

参考一贴中汇总的帖子内容,其实在 debug 里逐步跟踪就能了解如何具体实现了,只是很累罢了。
其实我也只是 ...
CrLf 发表于 2013-1-21 20:02
  1. ,5Pj!]_jTX(C!!!
复制代码

TOP

回复 11# email10t


    脑子没转过来,忘了进制的区别。已修改,感谢指正~

TOP

来个构思详解:
---------------------------------------------------------------------------
臭不要脸 ...
CrLf 发表于 2014-11-23 00:25



   
只用 sub 也可以:
  1. sub ax,6060
  2. sub ax,6060
  3. sub ax,3e40
复制代码
可以再无聊点:
  1. inc ax
  2. inc ax
  3. inc ax
  4. ... ;加256次
复制代码
1

评分人数

    • CrLf: 感谢指正!技术 + 1

TOP

本帖最后由 CrLf 于 2014-11-23 19:31 编辑

引申5:
因为寄存器有初始状态,cx=00ff  bp=091e  si=0100  sp=di=fffe(非Debug环境),所以:
如果要改变的内存地址在 0x120~0x17f 之间,就可以直接用 [si+N] 指向特定位置
0xff 也不需要辗转取得了,cl 初始值就是了,比较高效的办法是用 di 代替 cl,用 xor [Addr],di 一次修改两个相邻字节
---------------------------------------------------------------------
附上 寄存器状态显示.bat,关于实际运行时寄存器初始状态的结论就是用这个得到的
  1. @echo off&setlocal enabledelayedexpansion
  2. set com=vr.com
  3. cd .>!com!
  4. more +19 %0|debug !com!>nul
  5. for /f "tokens=1-14" %%a in ('!com!') do (
  6. set /a "F=0x%%n,CF=F&1,PF=(F>>2)&1,AF=(F>>4)&1,ZF=(F>>6)&1"
  7. set /a "SF=(F>>7)&1,TF=(F>>8)&1,IF=(F>>9)&1,DF=(F>>10)&1,OF=(F>>11)&1"
  8. for %%A in (
  9. CF-CY-NC PF-PE-PO AF-AC-NA ZF-ZR-NZ SF-NG-PL IF-EI-DI DF-DN-UP OF-OV-NV
  10. ) do (
  11. for /f "tokens=1-3 delims=-" %%B in ("%%A") do (
  12. if !%%B!==1 (set %%B=%%C) else set %%B=%%D
  13. )
  14. )
  15. echo AX=%%a  BX=%%b  CX=%%c  DX=%%d   SP=%%e  BP=%%f  SI=%%g  DI=%%h
  16. echo DS=%%i  ES=%%j  SS=%%k  CS=%%l   IP=%%m  !OF! !DF! !IF! !SF! !ZF! !AF! !PF! !CF!  TF=!TF!
  17. )
  18. del !com!>nul&pause&exit/b
  19. rds
  20. 1000
  21. rcs
  22. 1000
  23. eds:100 eb 37 50 b8 0 2 51 b9 10 0 83 e9 4 52 d3 ca
  24. eds:110 81 e2 f 0 80 fa a 72 3 80 c2 7 80 c2 30 cd
  25. eds:120 21 5a 41 e2 e5 59 52 b8 0 2 ba 20 0 cd 21 58
  26. eds:130 5a c3 5a 52 83 ea 7e eb c9 9c 8f 6 0 2 52 89
  27. eds:140 c2 e8 be ff 89 da e8 b9 ff 89 ca e8 b4 ff 5a e8
  28. eds:150 b0 ff 89 e2 e8 ab ff 50 89 ea e8 a5 ff 89 f2 e8
  29. eds:160 a0 ff 89 fa e8 9b ff 8c da e8 96 ff 8c c2 e8 91
  30. eds:170 ff 8c d2 e8 8c ff 8c ca e8 87 ff e8 b4 ff 8b 16
  31. eds:180 0 2 e8 7d ff cd 20
  32. rcx
  33. 87
  34. w
  35. q
  36. 原型:
  37. jmp 139; main;;;;
  38. push ax ;fun
  39. mov ax,200
  40. push cx
  41. mov cx,10
  42. sub cx,4   ;view
  43. push dx
  44. ror dx,cl
  45. and dx,f
  46. cmp dl,a
  47. jb 11c   ;next;;; don't add 7
  48. add dl,7
  49. add dl,30;------
  50. int 21
  51. pop dx
  52. inc cx
  53. loop 10a; view;;;
  54. pop cx
  55. push dx
  56. mov ax,200
  57. mov dx,20
  58. int 21
  59. pop ax
  60. pop dx
  61. ret;;;end fun
  62. pop dx
  63. push dx
  64. sub dx,7e
  65. jmp 102; fun;;;
  66. pushf   ;main
  67. pop [200]
  68. push dx
  69. mov dx,ax
  70. call 102;fun;;;
  71. mov dx,bx
  72. call 102;fun;;;
  73. mov dx,cx
  74. call 102;fun;;;
  75. pop dx
  76. call 102;fun;;;
  77. mov dx,sp
  78. call 102;fun;;;
  79. push ax
  80. mov dx,bp
  81. call 102;fun;;;
  82. mov dx,si
  83. call 102;fun;;;
  84. mov dx,di
  85. call 102;fun;;;
  86. mov dx,ds
  87. call 102;fun;;;
  88. mov dx,es
  89. call 102;fun;;;
  90. mov dx,ss
  91. call 102;fun;;;
  92. mov dx,cs
  93. call 102;fun;;;
  94. call 132;rip
  95. mov dx,[200]
  96. call 102;fun;;;
  97. int 20
复制代码

TOP

本帖最后由 CrLf 于 2014-11-23 18:05 编辑

引申4:
关于控制字符的特例:
水平制表符(0x09 Tab)、回车符(0x0a Cr)、换行符(0x0d Lf) 对绝大多数数编辑器来说是可见而有实际意义的,所以也可考虑用于 ascode,查表知道它们对应的是一些 or 指令
关于不可见字符的特例:
如果不考虑歪国人的使用环境,不可见字符在 gb2312 编码也不是完全不可见,只要你能组成汉字或者中文标点之类合法的宽字符,同样能把大于 0x7f 的字符用在 ascode 里,这样就能大大简化转换的过程

TOP

本帖最后由 CrLf 于 2014-11-23 02:07 编辑

引申3:
人工构造 ascode 比较费劲,需要边写边推算运行时的变化,如果有跳转或者长度超出预期就更复杂了
所以产生了一些算法来自动构造 ascode,个人觉得,最直观的思路应该是类似于加壳/脱壳,将机器码以特定的形式保存成可见字符,使用时再用头部的解释器把它翻译回来,代价是生成的 ascode 必须附加解释器部分,对小程序来说,解释器会比程序原始长度还长很多
我想过去应该还有另一种实现方式:为所有可能的汇编指令做出一个等价的模板,将实际指令逐条处理为模板中的格式,这样得到的结果比较接近于人工构造,但大概只适合小程序,碰到体积原本就不小的程序会膨胀得厉害,相比于加壳/脱壳方案更容易超过 64K 的程序大小限制
---------------------------------------------------------------------------
继续臭不要脸地给出本人拙作作为例子,此例就是加壳/脱壳式的思路:
ascode 的 encode/decode 算法2
还有此贴中 qzwqzw 大神给出的许多外文资料:
http://bbs.bathome.net/redirect. ... 1&fromuid=30406

TOP

本帖最后由 CrLf 于 2014-11-23 18:05 编辑

引申2:
ascode 的效率其实不高,16 位程序在 32 位系统里是用 ntvdm.exe 模拟 16 位环境来运行的,它的效率远没有 32 位程序快
到 64 位系统,windows 已经不对 16 位程序提供支持了,所以这个技术貌似是快走到尽头了
事实上,我觉得随着 powershell 的普及,ascode 的存在意义也不是那么大了,虽然 .ps1 脚本默认不能直接运行,但却可以在 cmd 中把 powershell 当外部命令用,这就涵盖了 ascode 能实现的不少功能

TOP

引申1:
除了通过 echo 输出到临时文件,还有一种办法是:
构造一个以 : 开头的 ascode,然后放在脚本头部,然后 copy %0 ascode.com 就行了
为什么能用 :,查 3 楼给出的列表得知它对应的是 cmp 指令,所以其实不限于 :,只要能找出汇编花指令对应的批处理合法语句都能这么做,比如前文提到的 @ECHO  OFF&REM  也可以改造成能够可用的批处理/ascode 混编脚本

TOP

本帖最后由 CrLf 于 2015-5-7 23:19 编辑

来个构思详解:
---------------------------------------------------------------------------
臭不要脸地以自己的帖子为例(掩面):
ascode 应用之 获取输入字符 getc.com
---------------------------------------------------------------------------
在这个 getc.com 中,我最终要实现的功能是:
  1. mov ah,1
  2. int 21
  3. ret
复制代码
其机器码为:
  1. B4 01 CD 21 C3
复制代码
一看就知道除了 21 (asc="!") 之外,其他四个字节都不是可见字符,那肿么办呢?表急,让我静下来想一想...
---------------------------------------------------------------------------
1、
嗯,mov ah,1 用很多命令都能实现,因为 ax 的初始状态是 0000,所以...
比较快的办法是用 xor:
  1. xor ax,3130
  2. xor ax,3030
复制代码
只用 sub 也可以:
  1. sub ax,6060
  2. sub ax,6060
  3. sub ax,3f40
复制代码
可以再无聊点:
  1. inc ax
  2. inc ax
  3. inc ax
  4. ... ;加256次
复制代码
因为最终需求是 ax=0100,所以这个特殊结果也可以取巧用 xor+aaa 实现:
  1. xor al,2a
  2. aaa
复制代码
引申一下,其实最无耻莫过于:
  1. push si
  2. pop ax
复制代码
为什么可以这样,这是因为执行十六位程序的时候,寄存器是有初始状态的,实际是这样的(DX=段寄存器,这几个是会变的,其他均恒定):
  1. AX=0000  BX=0000  CX=00FF  DX=0E1C   SP=FFFE  BP=091E  SI=0100  DI=FFFE
  2. DS=0E1C  ES=0E1C  SS=0E1C  CS=0E1C   IP=0100  NV UP EI PL NZ NA PO NC  TF=0
复制代码
要注意的是,实际执行十六位程序时的寄存器初始状态和在 debug 中表现的不太一样,debug 调试的时候是这样的:
  1. AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
  2. DS=13CC  ES=13CC  SS=13CC  CS=13CC  IP=0100   NV UP EI PL NZ NA PO NC
复制代码
这!很!重!要!
如果你的程序不需要操作 cx、dx、sp、bp、si、di 寄存器,那好吧,其实这个知不知道也无所谓了
---------------------------------------------------------------------------
2、
我们已经知道 mov ah,1 不一定要用 mov 实现,那 int 21 和 ret 呢?
貌似没有太直接的办法来代替它们,或者说即使有替代方案,指令也比较长,得不偿失
所以,重点就是怎么在代码段构建出 int 21 和 ret
---------------------------------------------------------------------------
3、
在我的构思中,代码的前半段都是在倒腾寄存器和内存,执行到最后会碰到生成的 int 21 和 ret
为了简化实现过程,在代码末尾附加了三个字节 33 21 3D,这样只需要对 33 和 3D 所在的内存位置做两次 xor [Addr],ff 就能把它变成 CD 21 C3,然后对 0xff 做一次 inc,就能得到梦寐以求的 0x0100
现在实现的关键就在于怎么得到 0xff 和怎么定位内存地址
地址可以通过 [(存储偏移地址的寄存器)+(一个可见字符对应的机器码)] 来定位,所以定位地址的问题就转化成怎么得到偏移地址的问题
至于 0xff...呵呵,这能叫障碍吗?
---------------------------------------------------------------------------
4、
因为 ax 是一定需要改变的,所以我决定把这两个辅助性的数值都放在 ax 寄存器中倒腾
首先取得偏移地址,因为 [(存储偏移地址的寄存器)+(一个可见字符对应的机器码)] 的值得大于 0x100,所以寄存器里的值一定要大于 0x80,考虑到解码部分的长度和可见字符的范围限制,它理想的范围是 0xa0~0xe0 之间,这个用 sub 指令可以轻松做到
将它存入 di 寄存器后,我们再来取得 0xff,通过前文的介绍,你一定知道怎么做
---------------------------------------------------------------------------
5、
万事俱备,只需要用取得的偏移地址+特定的偏移量定位内存地址,对我们希望是 int 21 和 ret 的地方做一次与 0xff 的 xor 运算即可
---------------------------------------------------------------------------
6、
做完运算后,已经得到了 int 21 和 ret,对值为 0xff 的 ax 寄存器做一次 inc 运算,效果等价于 mov ax,0100,表明即将调用的是 1 号功能
然后就是 int 21,调用 21 号中断
再然后是 ret,跳转到 CS:0000 地址处,调用 int 20 结束程序
---------------------------------------------------------------------------
7、
根据需求作一些微调,可避免出现特殊字符 < > " & | 等
---------------------------------------------------------------------------
来看最终成果:
  1. ,RP_4P0E`0Eb@@3!=
复制代码
它在 debug 里反汇编的结果是:
  1. 段地址:偏移地址 机器码     对应的汇编指令
  2. 13CC:0100 2C52          SUB     AL,52
  3. 13CC:0102 50            PUSH    AX
  4. 13CC:0103 5F            POP     DI
  5. 13CC:0104 3450          XOR     AL,50
  6. 13CC:0106 304560        XOR     [DI+60],AL
  7. 13CC:0109 304562        XOR     [DI+62],AL
  8. 13CC:010C 40            INC     AX
  9. 13CC:010D 40            INC     AX
  10. 13CC:010E 3321          XOR     SP,[BX+DI]
  11. 13CC:0110 3D0000        CMP     AX,0000
复制代码
运行一下试试,唔,效果不错,收工回家
---------------------------------------------------------------------------
仔细想了想其实可以简化成这样:
  1. VX0L[Tab字符]..瓮廾
  2. 实际使用时请吧 [Tab字符] 替换成一个 Tab 字符
复制代码
应用了引申4、引申5 和 2 楼列表中的结论和构想,因为含有 ansi 宽字符,所以精简版仅能在 936 代码页下生成正确的脚本
原先的 ascode 长 17 个字节,化简后长度为 11 个字节,而最原始的汇编原型为 5 个字节,看起来是精简到极致了,为什么这么短呢...我就不解释了,请自行研究吧
1

评分人数

    • amwfjhh: 睡前点赞,辛苦了,为了不破坏本文的完整性 ...技术 + 1

TOP

本帖最后由 CrLf 于 2014-11-23 00:25 编辑

前文提到的 "@ECHO  OFF&REM" 反汇编的结果是这样:
  1. inc ax
  2. inc bp
  3. inc bx
  4. dec ax
  5. dec di
  6. and [bx+si],ah
  7. dec di
  8. inc si
  9. inc si
  10. es:
  11. push dx
  12. inc bp
  13. dec bp
  14. and [bx+si],ah
复制代码
这是个特例,而且也没有太大的实际作用
如果不对代码段的内存内容进行篡改,那连 int 指令都用不了,基本上干不了什么事
所以构造 ascode 的基本思路是用可见字符对应的指令修改即将后续执行的代码段内存,将其拼凑出 ascode 中本不存在的真实的机器码

TOP

本帖最后由 CrLf 于 2016-7-14 13:31 编辑

贴一下以前测试得出的一点成果,其实顶楼已经提到了,只是比较概括
ascode可用指令大概有这些:
  1. *:  and sub xor cmp j*  daa das aaa  inc dec  push pop pusha popa imul insb insw outsb outsw
复制代码
可见字符和控制字符中的少数字符对应的指令是可以用于初始的 ascode 的,请见下表(这个结果是碰撞所得,可能不完整,但表中列出的应该都能用)

控制字符:
  1. 00-05 add *
  2. 06 push es
  3. 07 pop es
  4. 08-0d or *
  5. 0e push cs
  6. 0f 无
  7. 10-15 adc *
  8. 16 push ss
  9. 17 pop ss
  10. 18-1d sbb *
  11. 1e push ds
  12. 1f pop ds
复制代码
可见字符:
  1. 20-25 and *
  2. 26 es:
  3. 27 daa
  4. 28-2d sub *
  5. 2e cs:
  6. 2f das
  7. 30-35 xor *
  8. 36 ss:
  9. 37 aaa
  10. 38-3d cmp [*],*
  11. 3e ds:
  12. 3f aas
  13. 40 inc ax
  14. 41 inc cx
  15. 42 inc dx
  16. 43 inc bx
  17. 44 inc sp
  18. 45 inc bp
  19. 46 inc si
  20. 47 inc di
  21. 48 dec ax
  22. 49 dec cx
  23. 4a dec dx
  24. 4b dec bx
  25. 4c dec sp
  26. 4d dec bp
  27. 4e dec si
  28. 4f dec di
  29. 50 push ax
  30. 51 push cx
  31. 52 push dx
  32. 53 push bx
  33. 54 push sp
  34. 55 push bp
  35. 56 push si
  36. 57 push di
  37. 58 pop ax
  38. 59 pop cx
  39. 5a pop dx
  40. 5b pop bx
  41. 5c pop sp
  42. 5d pop bp
  43. 5e pop si
  44. 5f pop di
  45. /********
  46. 区间 60~6f 由 email10t 在本贴 16 楼补充
  47. 区间 62、63、66、67 由 sj157250 在本贴 34 楼继续补充
  48. debug 无法正常汇编/反汇编这部分的指令,但可以正常运行
  49. 60 pusha
  50. 61 popa
  51. 62 BOUND
  52. 63 ARPL Ew,Rw
  53. 64 fs:
  54. 65 gs:
  55. 66 push dword * | Operand Size Prefix
  56. 67 imul dword * | Address Size Prefix
  57. 68 push word *
  58. 69 imul word *
  59. 6a push byte *
  60. 6b imul byte *
  61. 6c insb
  62. 6d insw
  63. 6e outsb
  64. 6f outsw
  65. 区间结束
  66. **********/
  67. 70 jo
  68. 71 jno
  69. 72 jb
  70. 73 jnb
  71. 74 jz
  72. 75 jnz
  73. 76 jbe
  74. 77 ja
  75. 78 js
  76. 79 jns
  77. 7a jpe
  78. 7b jpo
  79. 7c jl
  80. 7d jge
  81. 7e jle
  82. 7f jg
复制代码
不可见字符:
  1. 80-83 and word ptr *
  2. 84-85 test *
  3. 86-87 xchg *
  4. 88-8c mov *
  5. 8d lea *
  6. 8e mov
  7. 8f pop [*]
  8. 8f pop [*]
  9. 90 nop
  10. 91-97 xchg *
  11. 98 cbw
  12. 99 cwd
  13. 9a call
  14. 9b wait
  15. 9c pushf
  16. 9d popf
  17. 9e sahf
  18. 9f lahf
  19. a0-a3 mov *
  20. a4 movsb
  21. a5 movsw
  22. a6 cmpsb
  23. a7 cmpsw
  24. a8-a9 test *
  25. aa stosb
  26. ab stosw
  27. ac lodsb
  28. ad lodsw
  29. ae scasb
  30. af scasw
  31. b0-bf mov *
  32. c0-c1 无
  33. c2 ret *
  34. c3 ret
  35. c4 les *
  36. c5 lds *
  37. c6-c7 mov *
  38. c8-c9 无
  39. ca retf *
  40. cb retf
  41. cc int 3
  42. cd int *
  43. ce into
  44. cf iret
  45. d0-d3 shl *  (d0 ror;d2 rol)
  46. d4 aam *
  47. d5 aad
  48. d6 无
  49. d7 xlat
  50. d8 fsub dword ptr *
  51. d9 fldenv *
  52. da fisub dword ptr *
  53. db esc *
  54. dc fsub qword ptr *
  55. dd frstor *
  56. de fisub word ptr *
  57. df fbld tbyte ptr *
  58. e0 loopnz *
  59. e1 loopz *
  60. e2 loop *
  61. e3 jcxz
  62. e4-e5 in *
  63. e6-e7 out *
  64. e8 call *
  65. e9-eb jmp *
  66. ec-ed in *
  67. ee-ef out *
  68. f0 lock
  69. f1 无
  70. f2 repnz
  71. f3 repz
  72. f4 hlt
  73. f5 cmc
  74. f6 mul byte ptr *
  75. f7 mul word ptr *
  76. f8 clc
  77. f9 stc
  78. fa cli
  79. fb sti
  80. fc cld
  81. fd std
  82. fe-ff jmp [*]
复制代码
x86 的部分指令列表参见 pcl_test 在 35 楼的回帖

TOP

本帖最后由 CrLf 于 2014-11-26 00:32 编辑

附上 demon 大师的博文链接:ASCII Assembly技术简介
可惜那个“下面的网站总结了每个可打印的ASCII字符所对应的汇编指令”的链接失效了,印象中内容很详尽,当时直接导致我放弃更新此贴
---------------------------------------------------------------------
本站站内搜索 ascode 和 ascii assembly 得到这些相关帖子链接:
输入密码但不显示既隐藏输入密码的批处理(20090420)
屏蔽命令行密码 5楼
小型二进制文件ASCII编码器
【挑战】批处理如何创建仅含一个nul字符的文件 14楼
批处理与其他语言混合编程2
[方案汇总]批处理隐藏运行的11种思路(2009-04-18)
怎样让屏显的结果的同时写入到到文件中?
文本转URL编码
批处理用set代替choice怎么写?
求一段识别文件类型的BAT代码,也就是判断后缀名
批处理中 回车键的问题
[挑战]如何不换行输出以等号或引号开头的行? 14楼
只1k的延迟程序:sleep.com
ascode 的一些资料汇编
ascode 的 encode/decode 算法
ascode 的 encode/decode 算法2
ascode 应用之 仿控制台全屏效果 full.com
ascode 应用之 获取输入字符 getch.com
ascode 应用之 获取输入字符 getc.com
ascode 应用之 不换行显示字符串 put.com
ascode 应用之 将光标移动到指定位置 xy.com
ascode 应用之 存取文件 encode.com/decode.com
ascode 应用之 界面神器syxq便携版 syxq.com (Portable)

TOP

返回列表