参考文章地址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生成他的汇编

  1. MBR:0000 jmp far ptr 7C0h:5
  2. MBR:0005 ; ---------------------------------------------------------------------------
  3. MBR:0005 mov ax, cs
  4. MBR:0007 mov ds, ax
  5. MBR:0009 mov ss, ax
  6. MBR:000B mov sp, 400h
  7. MBR:000E cld
  8. MBR:000F mov ax, 3
  9. MBR:0012 int 10h ; - VIDEO - SET VIDEO MODE
  10. MBR:0012 ; AL = mode
  11. MBR:0014 mov dx, 0
  12. MBR:0017 mov cx, 2
  13. MBR:001A mov ax, 1000h
  14. MBR:001D mov es, ax
  15. MBR:001F assume es:nothing
  16. MBR:001F xor bx, bx
  17. MBR:0021 mov ax, 228h
  18. MBR:0024 int 13h ; DISK - READ SECTORS INTO MEMORY
  19. MBR:0024 ; AL = number of sectors to read, CH = track, CL = sector
  20. MBR:0024 ; DH = head, DL = drive, ES:BX -> buffer to fill
  21. MBR:0024 ; Return: CF set on error, AH = status, AL = number of sectors read
  22. MBR:0026 jnb short loc_2A
  23. MBR:0028
  24. MBR:0028 loc_28: ; CODE XREF: MBR:loc_28j
  25. MBR:0028 jmp short loc_28
  26. MBR:002A ; ---------------------------------------------------------------------------
  27. MBR:002A
  28. MBR:002A loc_2A: ; CODE XREF: MBR:0026j
  29. MBR:002A cli
  30. MBR:002B mov ax, 1000h
  31. MBR:002E mov ds, ax
  32. MBR:0030 assume ds:nothing
  33. MBR:0030 xor ax, ax
  34. MBR:0032 mov es, ax
  35. MBR:0034 assume es:nothing
  36. MBR:0034 mov cx, 2000h
  37. MBR:0037 sub si, si
  38. MBR:0039 sub di, di
  39. MBR:003B rep movsb
  40. MBR:003D mov ax, 7C0h
  41. MBR:0040
  42. MBR:0040 loc_40: ; DATA XREF: MBR:0012r
  43. MBR:0040 mov ds, ax
  44. MBR:0042 assume ds:nothing
  45. MBR:0042 lidt fword ptr ds:6Fh
  46. MBR:0047 lgdt fword ptr ds:75h
  47. MBR:004C
  48. MBR:004C loc_4C: ; DATA XREF: MBR:0024r
  49. MBR:004C mov ax, 1
  50. MBR:004F lmsw ax
  51. 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进行重建

  1. main:00000200 mov eax, 10h
  2. main:00000205 mov ds, eax
  3. main:00000207 assume ds:nothing
  4. main:00000207 lss esp, large ds:0B5Ch
  5. main:0000020E call sub_28B
  6. main:00000213 call sub_283
  7. main:00000218 mov eax, 10h ; DATA XREF: sub_28B+27r
  8. main:0000021D mov ds, eax
  9. main:0000021F mov es, eax
  10. main:00000221 assume es:nothing
  11. main:00000221 mov fs, eax ; DATA XREF: sub_283r
  12. main:00000223 assume fs:nothing
  13. main:00000223 mov gs, eax
  14. main:00000225 assume gs:nothing
  15. main:00000225
  16. main:00000225 loc_225: ; DATA XREF: sub_28B+11o
  17. main:00000225 lss esp, large ds:0B5Ch
  18. main:0000022C xor ebx, ebx
  19. main:0000022E
  20. main:0000022E loc_22E: ; CODE XREF: sub_200+5Dj
  21. main:0000022E nop
  22. main:0000022F cmp ebx, 10h
  23. main:00000232 jge short loc_25F
  24. main:00000234 mov eax, 80000h
  25. main:00000239 lea edx, ds:0D08h[ebx*4]
  26. main:00000240 mov edx, [edx]
  27. main:00000242 mov ax, dx
  28. main:00000245 mov dx, 8E00h
  29. main:00000249 mov ecx, 21h ; '!'
  30. main:0000024E add ecx, ebx
  31. main:00000250 lea esi, ds:128h[ecx*8]
  32. main:00000257 mov [esi], eax
  33. main:00000259 mov [esi+4], edx
  34. main:0000025C inc ebx
  35. main:0000025D jmp short loc_22E
  36. main:0000025F ; ---------------------------------------------------------------------------
  37. main:0000025F
  38. main:0000025F loc_25F: ; CODE XREF: sub_200+32j
  39. main:0000025F ; sub_200+66j
  40. main:0000025F call sub_268
  41. main:00000264 int 21h ; DOS -
  42. main:00000266 jmp short loc_25F
  43. main:00000266 sub_200 endp

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

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

  1. main:0000028B mov edx, 0FCh
  2. main:00000290 mov eax, 80000h
  3. main:00000295 mov ax, dx
  4. main:00000298 mov dx, 8E00h
  5. main:0000029C lea edi, loc_225+3 - unk_100//地址为0x128
  6. main:000002A2 mov ecx, 100h
  7. main:000002A7
  8. main:000002A7 loc_2A7: ; CODE XREF: sub_28B+25j
  9. main:000002A7 mov [edi], eax
  10. main:000002A9 mov [edi+4], edx
  11. main:000002AC add edi, 8
  12. main:000002AF dec ecx
  13. main:000002B0 jnz short loc_2A7
  14. main:000002B2 lidt large fword ptr ds:11Ch
  15. main:000002B9 retn
  16. 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

  1. main:00000283 lgdt large fword ptr ds:122h
  2. main:0000028A retn
  3. 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函数

  1. sub_268 proc near ; CODE XREF: sub_200:loc_25Fp
  2. main:00000268 mov edi, large ds:0B78h
  3. main:0000026E lea edi, ds:0D48h[edi*4]
  4. main:00000275 mov eax, [edi]
  5. main:00000277 mov large ds:65h, al
  6. main:0000027C mov ecx, [edi+4]
  7. main:0000027F mov eax, [edi+8]
  8. main:00000282 retn
  9. main:00000282 sub_268 endp

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

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

  1. main:00000264 int 21h

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

  1. main:00000EF8 lea ecx, dword_C78 - unk_100
  2. main:00000EFE mov eax, [ecx]
  3. main:00000F00 add eax, 3
  4. main:00000F03 mov [ecx], eax
  5. 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下来写脚本将其流程打印出来 进行虚拟指令的处理

  1. data = [
  2. 0x00000021, 0x00000000, 0x00000081, 0x00000027, 0x00000001, 0x00000001, 0x00000024, 0x00000001, 0x00000001,
  3. 0x00000023, 0x00000002, 0x00000000, 0x00000022, 0x00000003, 0x00000002, 0x00000021, 0x00000004, 0x00000008,
  4. 0x00000028, 0x00000003, 0x00000004, 0x00000027, 0x00000002, 0x00000003, 0x00000028, 0x00000003, 0x00000004,
  5. 0x00000027, 0x00000002, 0x00000003, 0x00000028, 0x00000003, 0x00000004, 0x00000027, 0x00000002, 0x00000003,
  6. 0x00000027, 0x00000003, 0x00000003, 0x00000023, 0x00000004, 0x00000003, 0x00000024, 0x00000003, 0x00000002,
  7. 0x00000027, 0x00000002, 0x00000004, 0x00000024, 0x00000000, 0x00000002, 0x00000021, 0x00000001, 0x00000001,
  8. 0x00000025, 0x00000000, 0x00000001, 0x00000022, 0x00000001, 0x00000000, 0x00000021, 0x00000002, 0x00000081,
  9. 0x00000026, 0x00000001, 0x00000002, 0x00000021, 0x00000002, 0x00000009, 0x00000026, 0x00000001, 0x00000002,
  10. 0x00000021, 0x00000002, 0x00000009, 0x0000002D, 0x00000002, 0x00000001, 0x00000021, 0x00000000, 0x00000081,
  11. 0x00000022, 0x00000001, 0x00000000, 0x00000021, 0x00000002, 0x00000009, 0x00000025, 0x00000001, 0x00000002,
  12. 0x00000023, 0x00000003, 0x00000000, 0x00000023, 0x00000004, 0x00000001, 0x00000026, 0x00000003, 0x00000004,
  13. 0x00000021, 0x00000004, 0x0000007E, 0x0000002D, 0x00000004, 0x00000003, 0x00000021, 0x00000003, 0x00000001,
  14. 0x00000025, 0x00000000, 0x00000003, 0x00000025, 0x00000001, 0x00000003, 0x00000026, 0x00000002, 0x00000003,
  15. 0x00000021, 0x00000004, 0x0000005A, 0x0000002D, 0x00000004, 0x00000002, 0x0000002F, 0x00000000, 0x00000000,
  16. 0x00000030, 0x00000000, 0x00000000
  17. ]
  18. i = 0
  19. while (i<=126):
  20. if data[i] == 0x21:
  21. print ("buf[%d]=%d" % (data[i+1], data[i+2]))
  22. if data[i] == 0x22:
  23. print ("buf[%d]=buf[%d]" % (data[i+1], data[i+2]))
  24. if data[i] == 0x23:
  25. print ("buf[%d]=code[buf[%d]]" % (data[i+1], data[i+2]))
  26. if data[i] == 0x24:
  27. print ("code[buf[%d]]=buf[%d]" % (data[i+1], data[i+2]))
  28. if data[i] == 0x25:
  29. print ("buf[%d]+=buf[%d]" % (data[i+1], data[i+2]))
  30. if data[i] == 0x26:
  31. print ("buf[%d]-=buf[%d]" % (data[i+1], data[i+2]))
  32. if data[i] == 0x27:
  33. print ("buf[%d]^=buf[%d]" % (data[i+1], data[i+2]))
  34. if data[i] == 0x28:
  35. print ("buf[%d]<<=buf[%d]" % (data[i+1], data[i+2]))
  36. if data[i] == 0x29:
  37. print ("buf[%d]>>=buf[%d]" % (data[i+1], data[i+2]))
  38. if data[i] == 0x2A:
  39. print ("buf[%d]&=buf[%d]" % (data[i+1], data[i+2]))
  40. if data[i] == 0x2B:
  41. print ("i =buf[%d]" % (data[i+1]))
  42. if data[i] == 0x2c:
  43. print ("if buf[%d]==0 i=buf[%d]" % (data[i+2], data[i+1]))
  44. if data[i] == 0x2d:
  45. print ("if buf[%d]!=0 i=buf[%d]" % (data[i+2], data[i+1]))
  46. if data[i] == 0x2e:
  47. print "pause"
  48. if data[i] == 0x2f:
  49. print "correct"
  50. if data[i] == 0x30:
  51. print "wrong"
  52. 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次比较。

解密脚本:

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

得到结果

0x34363065

0x61613564

0x3761352d

0x31312d32

0x392d3965

0x2d303032

0x39653838

0x30386566

0x66616566

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

国赛 strange_int的更多相关文章

  1. 湘潭邀请赛+蓝桥国赛总结暨ACM退役总结

    湘潭邀请赛已经过去三个星期,蓝桥也在上个星期结束,今天也是时候写一下总结了,这应该也是我的退役总结了~ --------------------------------湘潭邀请赛----------- ...

  2. 2018年数学建模国赛B题 智能RGV的动态调度策略

    第一种情况大致思路: 每秒判断各个CNC的状态,若工作完成或者是出于空闲状态下则向RGV发出一个请求.同时,RGV每秒判断自己的状态(上下料.移动.闲置.清洗等),如果是处于闲置状态,则启用调度算法, ...

  3. 2018年第九届蓝桥杯国赛总结(JavaB组)

    懒更,之前的删了补一个国赛总结 记yzm10的第一次国赛(赛点:首都经贸大学) 第一次就拿到了国一,运气不要太好~(同组lz学长豪取国特orz) 从省赛一路水过来,总算有了点成绩.其实最后一题有些遗憾 ...

  4. 国赛baby_pwn

    国赛baby_pwn-ret2_dl_runtime_resolve之ELF32_rel,Elf32_sym,伪造 0x01 ELF文件的动态链接之延迟绑定 在动态链接下,程序模块之间包含了大量的函数 ...

  5. 使用pwn_deploy_chroot部署国赛pwn比赛题目

    目录 使用pwn_deploy_chroot部署国赛pwn比赛题目 一.前言 二.Docker 三.部署镜像 四.pwn_deploy_chroot 五.check && exp 六. ...

  6. 第九届蓝桥杯国赛+第二天的第11届acm省赛的总结

    第九届蓝桥杯国赛+第二天的第11届acm省赛的总结 25号坐的去北京的火车,10个小时的火车,然后挤了快两个小时的地铁,最终达到了中国矿业大学旁边的订的房间.12个小时很难受,晕车症状有点严重,吃了快 ...

  7. 2019第十届蓝桥杯省赛及国赛个人总结(java-B组)

    省赛: 今年省赛的题目比18年简单的多,基本都是暴力枚举.BFS之类.还记得去年在山师考蓝桥杯,我这种辣鸡连题目都没看懂.本以为蓝桥会变得越来越难,没想到今年就被打脸了.今年省赛后面三个编程大题一个没 ...

  8. Python小白的数学建模课-A1.国赛赛题类型分析

    分析赛题类型,才能有的放矢. 评论区留下邮箱地址,送你国奖论文分析 『Python小白的数学建模课 @ Youcans』 带你从数模小白成为国赛达人. 1. 数模竞赛国赛 A题类型分析 年份 题目 要 ...

  9. 【备考06组01号】第四届蓝桥杯JAVA组A组国赛题解

    1.填算式 (1)题目描述     请看下面的算式:     (ABCD - EFGH) * XY = 900     每个字母代表一个0~9的数字,不同字母代表不同数字,首位不能为0.     比如 ...

随机推荐

  1. 题解 Luogu P3959 【宝藏】

    来一篇不那么慢的状压??? 话说这题根本没有紫题难度吧,数据还那么水 我是不会告诉你我被hack了 一看数据规模,n≤12,果断状压. 然后起点要枚举,就设dp状态: f[i][j]=以i为起点到j状 ...

  2. Go语言(基本数据类型)

    Go语言中有丰富的数据类型,除了基本的整型.浮点型.布尔型.字符串外,还有数组.切片.结构体.函数.map.通道(channel)等.Go 语言的基本类型和其他语言大同小异. 基本数据类型 整型 整型 ...

  3. docker深入学习三

    docker学习三:network docker支持容器之间的网络通信,docker的网络通信方式有以下五种: bridge docker 默认的网络驱动,如果不指定网络驱动,docker就会创建一个 ...

  4. Dubbo快速入门 四

    4.业务场景 4.1).提出需求 某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址: 我们现在 需要创建两个服务模块进行测试 模块 功能 订单服务web模块 创建订单等 用户服务servi ...

  5. Qt5 源代码自动跳转

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/nixiaoxianggong/articl ...

  6. 在jenkins中使用shell命令推送当前主机上的docker镜像到远程的Harbor私有仓库

    1.jenkins主机上的docker配置 先在Jenkins主机的docke上配置上Harbor私有仓库地址 cat /etc/docker/daemon.json { "insecure ...

  7. 有助于改善性能的Java代码技巧

    前言 程序的性能受到代码质量的直接影响.这次主要介绍一些代码编写的小技巧和惯例.虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升,因此还是值得关注的. 慎用异常 在Java开发中,经 ...

  8. Java Web 深入分析(11) JVM(1)

    前言 Java启动后作为一个进程运行在操作系统中,该进程要分配的内存有以下几个: 1.Java堆: 存储java内存区域,堆大小是在jvm启动时就像操作系统申请完成,其中 -Xmx和-Xms 分别表示 ...

  9. Wireless support

    Wireless support 参考: https://www.rhyous.com/2010/12/03/freebsd-wireless-configuring-a-wireless-inter ...

  10. 【洛谷 P4302】 [SCOI2003]字符串折叠(DP)

    题目链接 简单区间dp 令\(f[i][j]\)表示\([i,j]\)的最短长度 先枚举区间,然后在区间中枚举长度\(k\),看这个区间能不能折叠成几个长度为\(k\)的,如果能就更新答案. #inc ...