参考文章地址https://www.52pojie.cn/thread-936377-1-1.html

https://qrzbing.cn/2019/04/27/CISCN2019-strange-int/

下载拿到文件使用linux file命令查看一下文件类型

为DOS/MBR主引导扇区。

放入winhex中查看,发现偏移0x1FE处有55 AA 表示这是一个分区,且主引导扇区的大小位512字节,可以判断前面为主引导记录的代码。

将程序放入IDA中,使用ALT+S修改0-0x200为16位分析的断,并右击code生成他的汇编

MBR:0000                 jmp     far ptr 7C0h:5
MBR:0005 ; ---------------------------------------------------------------------------
MBR:0005 mov ax, cs
MBR:0007 mov ds, ax
MBR:0009 mov ss, ax
MBR:000B mov sp, 400h
MBR:000E cld
MBR:000F mov ax, 3
MBR:0012 int 10h ; - VIDEO - SET VIDEO MODE
MBR:0012 ; AL = mode
MBR:0014 mov dx, 0
MBR:0017 mov cx, 2
MBR:001A mov ax, 1000h
MBR:001D mov es, ax
MBR:001F assume es:nothing
MBR:001F xor bx, bx
MBR:0021 mov ax, 228h
MBR:0024 int 13h ; DISK - READ SECTORS INTO MEMORY
MBR:0024 ; AL = number of sectors to read, CH = track, CL = sector
MBR:0024 ; DH = head, DL = drive, ES:BX -> buffer to fill
MBR:0024 ; Return: CF set on error, AH = status, AL = number of sectors read
MBR:0026 jnb short loc_2A
MBR:0028
MBR:0028 loc_28: ; CODE XREF: MBR:loc_28↓j
MBR:0028 jmp short loc_28
MBR:002A ; ---------------------------------------------------------------------------
MBR:002A
MBR:002A loc_2A: ; CODE XREF: MBR:0026↑j
MBR:002A cli
MBR:002B mov ax, 1000h
MBR:002E mov ds, ax
MBR:0030 assume ds:nothing
MBR:0030 xor ax, ax
MBR:0032 mov es, ax
MBR:0034 assume es:nothing
MBR:0034 mov cx, 2000h
MBR:0037 sub si, si
MBR:0039 sub di, di
MBR:003B rep movsb
MBR:003D mov ax, 7C0h
MBR:0040
MBR:0040 loc_40: ; DATA XREF: MBR:0012↑r
MBR:0040 mov ds, ax
MBR:0042 assume ds:nothing
MBR:0042 lidt fword ptr ds:6Fh
MBR:0047 lgdt fword ptr ds:75h
MBR:004C
MBR:004C loc_4C: ; DATA XREF: MBR:0024↑r
MBR:004C mov ax, 1
MBR:004F lmsw ax
MBR:0052 jmp far ptr 8:0

首先主引导扇区的地址被加载到0x7c00,跳转的目标地址是0x7c05,之后初始化段寄存器和栈指针,之后int 10h 调用bios中断设置显示模式。

之后int13h,使得将软盘(DL=0H) 上的0磁道(DH=0H)0柱面(CH=0H)2扇区(CL=2H)开始的28个扇区(AL=28H)读取(AH=02H)到内存的1000:0000h处(ES:BX=1000:0)。之后实现跳转

将DS:SI(1000:0)这段地址移动到ES:DI(0:0)处,移动了2000字节(cx=2000h)

接着初始化IDT和GDT(lidt,lgdt)之后开启保护模式(Imsw)并且跳转至32位代码段 从0x200开始

使用ALT+S进行重建

main:00000200                 mov     eax, 10h
main:00000205 mov ds, eax
main:00000207 assume ds:nothing
main:00000207 lss esp, large ds:0B5Ch
main:0000020E call sub_28B
main:00000213 call sub_283
main:00000218 mov eax, 10h ; DATA XREF: sub_28B+27↓r
main:0000021D mov ds, eax
main:0000021F mov es, eax
main:00000221 assume es:nothing
main:00000221 mov fs, eax ; DATA XREF: sub_283↓r
main:00000223 assume fs:nothing
main:00000223 mov gs, eax
main:00000225 assume gs:nothing
main:00000225
main:00000225 loc_225: ; DATA XREF: sub_28B+11↓o
main:00000225 lss esp, large ds:0B5Ch
main:0000022C xor ebx, ebx
main:0000022E
main:0000022E loc_22E: ; CODE XREF: sub_200+5D↓j
main:0000022E nop
main:0000022F cmp ebx, 10h
main:00000232 jge short loc_25F
main:00000234 mov eax, 80000h
main:00000239 lea edx, ds:0D08h[ebx*4]
main:00000240 mov edx, [edx]
main:00000242 mov ax, dx
main:00000245 mov dx, 8E00h
main:00000249 mov ecx, 21h ; '!'
main:0000024E add ecx, ebx
main:00000250 lea esi, ds:128h[ecx*8]
main:00000257 mov [esi], eax
main:00000259 mov [esi+4], edx
main:0000025C inc ebx
main:0000025D jmp short loc_22E
main:0000025F ; ---------------------------------------------------------------------------
main:0000025F
main:0000025F loc_25F: ; CODE XREF: sub_200+32↑j
main:0000025F ; sub_200+66↓j
main:0000025F call sub_268
main:00000264 int 21h ; DOS -
main:00000266 jmp short loc_25F
main:00000266 sub_200 endp

首先进行初始化 sub_28B和sub_283分别对LIDT和LGDT进行初始化。

首先看sub_28b,初始化中断描述符表

main:0000028B                 mov     edx, 0FCh
main:00000290 mov eax, 80000h
main:00000295 mov ax, dx
main:00000298 mov dx, 8E00h
main:0000029C lea edi, loc_225+3 - unk_100//地址为0x128
main:000002A2 mov ecx, 100h
main:000002A7
main:000002A7 loc_2A7: ; CODE XREF: sub_28B+25↓j
main:000002A7 mov [edi], eax
main:000002A9 mov [edi+4], edx
main:000002AC add edi, 8
main:000002AF dec ecx
main:000002B0 jnz short loc_2A7
main:000002B2 lidt large fword ptr ds:11Ch
main:000002B9 retn
main:000002B9 sub_28B endp

循环了256次,使得ds:[128]处地址填充为800fch之后填充8e00h。

然后加载中断描述符寄存器地址为ds:[11c]。

查看寄存器FF 07 28 01 00 00 1F 00

参考文章操作系统之GDT和IDT

代码段选择器(IDT表基地址)为0x0128

之后再看GDT

main:00000283                 lgdt    large fword ptr ds:122h
main:0000028A retn
main:0000028A sub_283 endp

只有简短的三行 寄存器地址为 ds:[0x122]

1F 00 28 09 00 00 00

基址为0x0928长度为0x1F

两个表初始化完毕之后继续向下看。

分别给ds,es,fs,gs赋值

后面是一个16次循环,分别将从内存中ds:0xD08开始的数据填充到ds:0x128,而ds:0x128是IDT表基地址,执行后中断21h到30h的的入口地址全部改变

中断编号 入口地址
0x21 0xb7c
0x22 0x0B8A
0x23 0x0BA1
0X24 0X0BC1
0X25 0X0BE1
0X26 0X0BFC
0X27 0X0C17
0X28 0X0C32
0X29 0X0C4F
0X2A 0X0C6C
0X2B 0X0C84
0X2C 0X0C96
0X2D 0X0CB5
0X2E 0X0CF7
0X2F 0X0CE0
0X30 0X0CD4

继续向下分析,执行sub_268函数

sub_268         proc near               ; CODE XREF: sub_200:loc_25F↑p
main:00000268 mov edi, large ds:0B78h
main:0000026E lea edi, ds:0D48h[edi*4]
main:00000275 mov eax, [edi]
main:00000277 mov large ds:65h, al
main:0000027C mov ecx, [edi+4]
main:0000027F mov eax, [edi+8]
main:00000282 retn
main:00000282 sub_268 endp

函数从ds:0x0B78那获取值作为ds:0D48h的偏移,将ds:0D48h处的值分别赋值给 给ds:65h,ecx,eax

然而地址ds:65h地址为汇编

main:00000264                 int     21h

所以此处中断是随着 ds:0d48h[edi * 4]的值改变。此处便是虚拟机。而ecx,和eax就为其参数,之后将0B78处的值加3,从而执行0d48[edi*4]处的下一个中断

main:00000EF8                 lea     ecx, dword_C78 - unk_100
main:00000EFE mov eax, [ecx]
main:00000F00 add eax, 3
main:00000F03 mov [ecx], eax
main:00000F05 iret

于是我们对各个中断逐一分析,由于涉及0x0b64处地址较多将其简化为buf为DWORD型数组,ecx为c,eax为a

将0x0d48简化为code为DWORD型数组

中断编号 操作内容
0x21 buf[c]=a
0x22 buf[c]=buf[a]
0x23 buf[c]=code[buf[a]]
0x24 code[buf[c]]=buf[a]
0x25 buf[c]=buf[c]+buf[a]
0x26 buf[c]=buf[c]-buf[a]
0x27 buf[c]=buf[c]^buf[a]
0x28 buf[c]=buf[c]<<(buf[a]&0xFF)
0x29 buf[c]=buf[c]>>(buf[a]&0xFF)
0x2A buf[c]=buf[c]&buf[a]
0x2B ds:0x0b78=buf[c]
0X2C if {buf[a]==0} ds:0x0b78=buf[c]
0X2D if{buf[a]!=0} ds:0x0b78=buf[c]
0X2E 暂停
0X2F 打印正确
0x30 打印错误

分析完毕之后,用Lazy IDA将数据dump下来写脚本将其流程打印出来 进行虚拟指令的处理

data = [
0x00000021, 0x00000000, 0x00000081, 0x00000027, 0x00000001, 0x00000001, 0x00000024, 0x00000001, 0x00000001,
0x00000023, 0x00000002, 0x00000000, 0x00000022, 0x00000003, 0x00000002, 0x00000021, 0x00000004, 0x00000008,
0x00000028, 0x00000003, 0x00000004, 0x00000027, 0x00000002, 0x00000003, 0x00000028, 0x00000003, 0x00000004,
0x00000027, 0x00000002, 0x00000003, 0x00000028, 0x00000003, 0x00000004, 0x00000027, 0x00000002, 0x00000003,
0x00000027, 0x00000003, 0x00000003, 0x00000023, 0x00000004, 0x00000003, 0x00000024, 0x00000003, 0x00000002,
0x00000027, 0x00000002, 0x00000004, 0x00000024, 0x00000000, 0x00000002, 0x00000021, 0x00000001, 0x00000001,
0x00000025, 0x00000000, 0x00000001, 0x00000022, 0x00000001, 0x00000000, 0x00000021, 0x00000002, 0x00000081,
0x00000026, 0x00000001, 0x00000002, 0x00000021, 0x00000002, 0x00000009, 0x00000026, 0x00000001, 0x00000002,
0x00000021, 0x00000002, 0x00000009, 0x0000002D, 0x00000002, 0x00000001, 0x00000021, 0x00000000, 0x00000081,
0x00000022, 0x00000001, 0x00000000, 0x00000021, 0x00000002, 0x00000009, 0x00000025, 0x00000001, 0x00000002,
0x00000023, 0x00000003, 0x00000000, 0x00000023, 0x00000004, 0x00000001, 0x00000026, 0x00000003, 0x00000004,
0x00000021, 0x00000004, 0x0000007E, 0x0000002D, 0x00000004, 0x00000003, 0x00000021, 0x00000003, 0x00000001,
0x00000025, 0x00000000, 0x00000003, 0x00000025, 0x00000001, 0x00000003, 0x00000026, 0x00000002, 0x00000003,
0x00000021, 0x00000004, 0x0000005A, 0x0000002D, 0x00000004, 0x00000002, 0x0000002F, 0x00000000, 0x00000000,
0x00000030, 0x00000000, 0x00000000
]
i = 0
while (i<=126):
if data[i] == 0x21:
print ("buf[%d]=%d" % (data[i+1], data[i+2]))
if data[i] == 0x22:
print ("buf[%d]=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x23:
print ("buf[%d]=code[buf[%d]]" % (data[i+1], data[i+2]))
if data[i] == 0x24:
print ("code[buf[%d]]=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x25:
print ("buf[%d]+=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x26:
print ("buf[%d]-=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x27:
print ("buf[%d]^=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x28:
print ("buf[%d]<<=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x29:
print ("buf[%d]>>=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x2A:
print ("buf[%d]&=buf[%d]" % (data[i+1], data[i+2]))
if data[i] == 0x2B:
print ("i =buf[%d]" % (data[i+1]))
if data[i] == 0x2c:
print ("if buf[%d]==0 i=buf[%d]" % (data[i+2], data[i+1]))
if data[i] == 0x2d:
print ("if buf[%d]!=0 i=buf[%d]" % (data[i+2], data[i+1]))
if data[i] == 0x2e:
print "pause"
if data[i] == 0x2f:
print "correct"
if data[i] == 0x30:
print "wrong"
i+=3

打印出结果如下

buf[0]=129

buf[1]^=buf[1]

code[buf[1]]=buf[1]

buf[2]=code[buf[0]]

buf[3]=buf[2]

buf[4]=8

buf[3]<<=buf[4]

buf[2]^=buf[3]

buf[3]<<=buf[4]

buf[2]^=buf[3]

buf[3]<<=buf[4]

buf[2]^=buf[3]

buf[3]^=buf[3]

buf[4]=code[buf[3]]

code[buf[3]]=buf[2]

buf[2]^=buf[4]

code[buf[0]]=buf[2]

buf[1]=1

buf[0]+=buf[1]

buf[1]=buf[0]

buf[2]=129

buf[1]-=buf[2]

buf[2]=9

buf[1]-=buf[2]

buf[2]=9

if buf[1]!=0 i=buf[2]

buf[0]=129

buf[1]=buf[0]

buf[2]=9

buf[1]+=buf[2]

buf[3]=code[buf[0]]

buf[4]=code[buf[1]]

buf[3]-=buf[4]

buf[4]=126

if buf[3]!=0 i=buf[4]

buf[3]=1

buf[0]+=buf[3]

buf[1]+=buf[3]

buf[2]-=buf[3]

buf[4]=90

if buf[2]!=0 i=buf[4]

correct

wrong

进行整理与分析,首先这串代码一共循环9次执行指令

code[i]=code[i] ^(code[i]<<8) ^ (code[i]<<16) ^(code[i]<<24) ^ code[i-1]

之后再执行9次比较

buf[i]与buf[i+9]进行9次比较。

解密脚本:

a=[0x57635565, 0x06530401, 0x1F494949, 0x5157071F, 0x575F4357, 0x57435E57, 0x4357020A, 0x575E035E,0x0f590000,0x0]
for x in range (0,9): m4=a[x]&0xff
m3=(a[x]&0xff00)>>8
m2=(a[x]&0xff0000)>>16
m1=(a[x]&0xff000000)>>24 p1=m4
p2=p1^m3
p3=p1^m2^p2
p4=p1^p2^p3^m1 flag=p1+(p2<<8)+(p3<<16)+(p4<<24)
print hex(flag)
a[x+1]=a[x]^a[x+1]

得到结果

0x34363065

0x61613564

0x3761352d

0x31312d32

0x392d3965

0x2d303032

0x39653838

0x30386566

0x66616566

将原文patch之后,放入boches之后运行即可提示成功

最新文章

  1. ZOJ 3686 A Simple Tree Problem
  2. undefined reference to `libiconv_open 无法编译PHP
  3. l5如何通过路由走api版本回退查找设置
  4. 【简易版】IOS仿periscope自制狂赞飘桃心
  5. 【转】如何修改Chrome缓存目录的地址
  6. Functions
  7. CentOS 5.x版本升级PHP
  8. 【转】HTTP-only Cookie 脚本获取JSESSIONID的方法
  9. Android Intent个人介绍
  10. 【原创】Hadoop机架感知对性能调优的理解
  11. Cacti添加threshold、monitor和setting
  12. Ubuntu最小化桌面快捷键Super+D不生效解决
  13. Excel中最精确的计算年龄的公式
  14. BCC校验小知识
  15. (3.14)mysql基础深入——mysql 日志分析工具之pt-querty-digest【待完善】
  16. 避免图片路径访问405,可以用图片控件来显示局部相对路径,不需要域名就不会出现jpg静态资源访问错误
  17. shared_ptr&amp;scoped_ptr&amp;weak_ptr
  18. 扫描算法(SCAN)——磁盘调度管理
  19. ARGB 8888 内存大小
  20. bzoj1656: [Usaco2006 Jan] The Grove 树木 (bfs+新姿势)

热门文章

  1. python学习-62 类属性的增 删 该 查
  2. Python小知识点+保留字
  3. 解决python中的Non-UTF-8 code starting with ‘\xbs4’ in file错误
  4. json转义问题
  5. docker postgres 导出导入数据
  6. 分享大麦UWP版本开发历程-03.GridView或ListView 滚动底部自动加载后续数据
  7. JSP 9大隐式对象和四个作用域的范围
  8. ③ Python3.0 数字类型
  9. Java 日期时间与unix时间戳之间转换
  10. apache-httpd代理请求,selinux造成503问题的解决方法