参考文章地址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的的入口地址全部改变

0x210xb7c
0x220x0B8A
0x230x0BA1
0X240X0BC1
0X250X0BE1
0X260X0BFC
0X270X0C17
0X280X0C32
0X290X0C4F
0X2A0X0C6C
0X2B0X0C84
0X2C0X0C96
0X2D0X0CB5
0X2E0X0CF7
0X2F0X0CE0
0X300X0CD4

继续向下分析,执行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型数组

0x21buf[c]=a
0x22buf[c]=buf[a]
0x23buf[c]=code[buf[a]]
0x24code[buf[c]]=buf[a]
0x25buf[c]=buf[c]+buf[a]
0x26buf[c]=buf[c]-buf[a]
0x27buf[c]=buf[c]^buf[a]
0x28buf[c]=buf[c]<<(buf[a]&0xFF)
0x29buf[c]=buf[c]>>(buf[a]&0xFF)
0x2Abuf[c]=buf[c]&buf[a]
0x2Bds:0x0b78=buf[c]
0X2Cif {buf[a]==0} ds:0x0b78=buf[c]
0X2Dif{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之后运行即可提示成功

12-18 03:52