Reference article addresses https://www.52pojie.cn/thread-936377-1-1.html
https://qrzbing.cn/2019/04/27/CISCN2019-strange-int/
download to get the file using the command linux file check file types
Boot sector of DOS / MBR master.
Winhex into view, there is found at offset 55 AA 0x1FE indicate a partition, boot sector and the main bit size of 512 bytes, the code can be determined based front boot record.
IDA into the program using ALT + S 16 to modify 0-0x200 off analysis, and right-click the assembler code generated his
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
First, the address of the master boot sector is loaded into 0x7C00, the jump target address is 0x7c05, after initialization segment registers and stack pointer, int 10h call bios interrupt after setting the display mode.
After int13h, 0 such that the track on the floppy (DL = 0H) (DH = 0H) 0 cylinder (CH = 0H) 2 sectors (CL = 2H) starting 28 sectors (AL = 28H) read ( AH = 02H) to 1000 memory: at 0000h (ES: BX = 1000: 0). After the realization Jump
The DS: SI (1000: 0) address to move this ES: DI (0: 0), the mobile 2,000 bytes (cx = 2000h)
Then, after initialization IDT and GDT (lidt, lgdt) open protection mode (Imsw) and jump to the code segment 32 from 0x200 started
using ALT + S reconstruction
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
First, initialize sub_28B and sub_283 respectively LIDT and LGDT initialized.
First look sub_28b, initialize the interrupt descriptor table
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
Cycle of 256 times, such ds: at [128] After the address of the padding to fill 8e00h 800fch.
Then loading the interrupt descriptor address register ds: [11c].
See register FF 07 28 01 00 00 1F 00
referenced article GDT and IDT an operating system
code segment selector (IDT table base address) 0x0128
Look after GDT
main:00000283 lgdt large fword ptr ds:122h
main:0000028A retn
main:0000028A sub_283 endp
Only short address register three lines DS: [0x122]
1F 00 28 09 00 00 00
base address 0x0928 length 0x1F
Continue to look down after two tables initialized.
Respectively, to ds, es, fs, gs assignment
followed by a 16 cycles, respectively, from memory ds: to start padding data 0xD08 ds: 0x128, and ds: IDT table base address 0x128 is, after execution of an interrupt 21h to 30h all change of address entry
Interrupt number | Entry address |
---|---|
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 |
Continue down analysis, execution sub_268 function
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
Function from ds: 0x0B78 that acquired value as ds: 0D48h offset, the ds: values are assigned to at 0D48h to ds: 65h, ecx, eax
however address ds: 65h address assembler
main:00000264 int 21h
So here it is interrupted with the ds: 0d48h [edi * 4] values change. Here is the virtual machine. And ecx, eax and on their parameters, after which at 0B78 value plus 3, to perform the next 0d48 [edi * 4] at break
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 ]! = I = 0 buf [. 4]
correct
Wrong
collation and analysis, this first string of code instructions executed a total of nine cycles
code [i] = code [i ] ^ (code [i] << 8) ^ (code [ i] << 16) ^ (code [i] << 24) ^ code [i-1]
after 9 then perform comparisons
buf [i] nine times compared with buf [i + 9].
Decryption script:
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]
Get results
0x34363065
0x61613564
0x3761352d
0x31312d32
0x392d3965
0x2d303032
0x39653838
0x30386566
0x66616566
after the original patch, after running into boches can prompt successful