• Home
  • About
    • tearorca photo

      tearorca

      Wishful thinking have to be willing to bet on clothing!

    • Learn More
    • Google+
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

南邮 汇编

28 Nov 2018

Reading time ~5 minutes

题目链接:https://pan.baidu.com/s/1UdIycPyVpSjSnt88cSqnyA 提取码:5o9v

南邮的一道16位汇编的题,也算是好好复习了一遍汇编,在64位上运行需要DosBox。于是在xp里面运行

,虽然是16位的程序,但还是可以用32位ida打开,不过不能F5只能看汇编。

不推荐纯看代码,太累了,还是推荐用动态调试,od不能用但还可以用windows最基本的debug调试。

基本命令:

-t是单句跟踪相当于F7

-p是不进入函数相当于F8

-d看内存的数据

-r看寄存器的值

我们可以发现有很多的int 21h,int 21h是汇编里面非常重要的一个中断,根据ah的值的不同进行不同的作用。具体可以参考:https://www.cnblogs.com/ynwlgh/archive/2011/12/12/2285017.html

我们一步一步往下运行可以发现

seg001:000C
seg001:000C
seg001:000C sub_100AC       proc near               ; CODE XREF: start+5↑p
seg001:000C                 mov     di, 3
seg001:000F                 call    sub_10115
seg001:0012                 mov     di, 24h ; '$'
seg001:0015                 call    sub_10123
seg001:0018                 mov     bx, 24h ; '$'
seg001:001B                 add     bx, 1
seg001:001E                 cmp     byte ptr [bx], 23h ; '#'
seg001:0021                 jnz     short loc_100DD
seg001:0023                 mov     di, 26h ; '&'
seg001:0026                 call    sub_100F9
seg001:0029                 mov     si, 76h ; 'v'
seg001:002C                 mov     dx, 23h ; '#'
seg001:002F                 call    sub_100E4
seg001:0032                 test    ax, ax
seg001:0034                 jnz     short loc_100DD
seg001:0036                 mov     di, 0Fh
seg001:0039                 call    sub_10115
seg001:003C                 retn

这段是主函数

seg001:0075 sub_10115       proc near               ; CODE XREF: sub_100AC+3↑p
seg001:0075                                         ; sub_100AC+2D↑p ...
seg001:0075                 mov     dx, di
seg001:0077                 mov     ah, 9
seg001:0079                 int     21h             ; DOS - PRINT STRING
seg001:0079                                         ; DS:DX -> string terminated by "$"
seg001:007B                 mov     dx, 0
seg001:007E                 mov     ah, 9
seg001:0080                 int     21h             ; DOS - PRINT STRING
seg001:0080                                         ; DS:DX -> string terminated by "$"
seg001:0082                 retn
seg001:0082 sub_10115       endp

这段是显示字符串的。

seg001:0083 sub_10123       proc near               ; CODE XREF: sub_100AC+9↑p
seg001:0083                 mov     dx, di
seg001:0085                 mov     ah, 0Ah
seg001:0087                 int     21h             ; DOS - BUFFERED KEYBOARD INPUT
seg001:0087                                         ; DS:DX -> buffer
seg001:0089                 mov     bx, di
seg001:008B                 add     bx, 1
seg001:008E                 xor     cx, cx
seg001:0090                 mov     cl, [bx]
seg001:0092                 add     bx, cx
seg001:0094                 add     bx, 1
seg001:0097                 mov     byte ptr [bx], 24h ; '$'
seg001:009A                 mov     dx, 0
seg001:009D                 mov     ah, 9
seg001:009F                 int     21h             ; DOS - PRINT STRING
seg001:009F                                         ; DS:DX -> string terminated by "$"
seg001:00A1                 retn

这段是要求我们输入字符串的。比较坑的就是当你输入完字符串后,当前字符串第一个字符的前一个地址存的是输入字符串的长度,之前一直不知道,所以在这上面掉坑里了。

这是debug下的一段指令,内存0B3F:0025就是输入字符串的长度
-p
ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789
AX=0A0D  BX=0000  CX=0142  DX=0024  SP=FFFC  BP=0000  SI=0000  DI=0024
DS=0B3F  ES=0B2F  SS=0B3F  CS=0B49  IP=0089   NV UP EI PL NZ NA PO NC
0B49:0089 8BDF          MOV     BX,DI
-D 0B3F:0025
0B3F:0020                 23 41 42-43 44 45 46 47 48 49 4A        #ABCDEFGHIJ
0B3F:0030  4B 4C 4D 4E 4F 50 51 52-53 54 55 56 57 58 59 5A   KLMNOPQRSTUVWXYZ
0B3F:0040  31 32 33 34 35 36 37 38-39 0D 00 00 00 00 00 00   123456789.......
0B3F:0050  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
0B3F:0060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
0B3F:0070  00 00 00 00 00 00 C9 68-8A C8 6F 07 06 0F 07 C6   .......h..o.....
0B3F:0080  EB 86 6E 6E 66 AD 4C 8D-AC EB 26 6E EB CC AE CD   ..nnf.L...&n....
0B3F:0090  8C 86 AD 66 CD 8E 86 8D-AF 00 00 00 00 00 00 00   ...f............
0B3F:00A0  B8 3F 0B 8E D8                                    .?...

走完输入的函数之后会有一个判断

seg001:0015                 call    sub_10123
seg001:0018                 mov     bx, 24h ; '$'
seg001:001B                 add     bx, 1
seg001:001E                 cmp     byte ptr [bx], 23h ; '#'
seg001:0021                 jnz     short loc_100DD

其实也就是判断字符串的长度是否为0x23

seg001:0059 sub_100F9       proc near               ; CODE XREF: sub_100AC+1A↑p
seg001:0059                 mov     bx, di
seg001:005B                 mov     si, 0
seg001:005E
seg001:005E loc_100FE:                              ; CODE XREF: sub_100F9+19↓j
seg001:005E                 mov     al, [bx+si]
seg001:0060                 mov     dl, al
seg001:0062                 mov     cl, 3
seg001:0064                 shr     al, cl
seg001:0066                 mov     cl, 5
seg001:0068                 shl     dl, cl
seg001:006A                 xor     al, dl
seg001:006C                 mov     [bx+si], al
seg001:006E                 inc     si
seg001:006F                 cmp     si, 23h ; '#'
seg001:0072                 jnz     short loc_100FE
seg001:0074                 retn
seg001:0074 sub_100F9       endp

这个函数是把你输入的字符串单个的取出来,然后进行移位操作,右移3位和左移5位。然后把两个数异或之后再存到原来的地址里面。这里要考虑一个问题,就是因为用的是al,只有8位所以将一个数左移5位可能会超过8位,那就会只截取后面8位。所以后面再写脚本的时候需要在移位之后&0xFF就可以了。最后就剩一个比较函数了

seg001:0029                 mov     si, 76h ; 'v'
seg001:002C                 mov     dx, 23h ; '#'
seg001:0044 sub_100E4       proc near               ; CODE XREF: sub_100AC+23↑p
seg001:0044                 xor     bx, bx
seg001:0046
seg001:0046 loc_100E6:                              ; CODE XREF: sub_100E4+B↓j
seg001:0046                 mov     al, [bx+si]
seg001:0048                 cmp     al, [bx+di]
seg001:004A                 jnz     short loc_100F5
seg001:004C                 inc     bx
seg001:004D                 cmp     bx, dx
seg001:004F                 jnz     short loc_100E6
seg001:0051                 mov     ax, 0
seg001:0054                 retn

这里di代表的偏移位置是经过异或之后的字符串,si偏移的位置的数据可以在ida这里找

000:0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ……………. 000:0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ……………. 000:0070 00 00 00 00 00 00 C9 68 8A C8 6F 07 06 0F 07 C6 ……蒱 娙 o… 000:0080 EB 86 6E 6E 66 AD 4C 8D AC EB 26 6E EB CC AE CD 雴 nnf璍 崿 ..n胩
000:0090 8C 86 AD 66 CD 8E 86 8D AF 00 00 00 00 00 00 00 寙 璮 蛶 啀 ….

也可以在debug里面找

AX=0928  BX=0000  CX=0005  DX=0023  SP=FFFC  BP=0000  SI=0076  DI=0026
DS=0B3F  ES=0B2F  SS=0B3F  CS=0B49  IP=0046   NV UP EI PL ZR NA PE NC
0B49:0046 8A00          MOV     AL,[BX+SI]                         DS:0076=C9
-d 0B3F:0076
0B3F:0070                    C9 68-8A C8 6F 07 06 0F 07 C6         .h..o.....
0B3F:0080  EB 86 6E 6E 66 AD 4C 8D-AC EB 26 6E EB CC AE CD   ..nnf.L...&n....
0B3F:0090  8C 86 AD 66 CD 8E 86 8D-AF 00 00 00 00 00 00 00   ...f............
0B3F:00A0  B8 3F 0B 8E D8 E8 04 00-B4 4C CD 21 BF 03 00 E8   .?.......L.!....
0B3F:00B0  63 00 BF 24 00 E8 6B 00-BB 24 00 83 C3 01 80 3F   c..$..k..$.....?
0B3F:00C0  23 75 1A BF 26 00 E8 30-00 BE 76 00 BA 23 00 E8   #u..&..0..v..#..
0B3F:00D0  12 00 85 C0 75 07 BF 0F-00 E8 39 00 C3 BF 18 00   ....u.....9.....
0B3F:00E0  E8 32 00 C3 33 DB 8A 00-3A 01 75 09 43 3B DA 75   .2..3...:.u.C;.u
0B3F:00F0  F5 B8 00 00 C3 B8                                 ......

最后就可以写脚本了,数据不大,可以直接爆破。

脚本:

l1='C9 68 8A C8 6F 07 06 0F 07 C6 EB 86 6E 6E 66 AD 4C 8D AC EB 26 6E EB CC AE CD 8C 86 AD 66 CD 8E 86 8D AF'

l2=l1.split(' ')

#print(l2)

flag=[]

for i in range(35):

	for j in range(33,256):
		
		a=j>>3&0xFF
		
		b=j<<5&0xFF
		
		c=a^b
	
	if c==int(l2[i],16): \#把16进制转成10进制
		
		flag.append(chr(j))
		
		break

print(''.join(flag))

再给一个这题c代码的原型

#include <stdio.h>

#include <string.h>

int main()

{
	
	puts("Input Flag:");
	
	char flag[35];
	
	int flag2[35];
	
	scanf("%s", flag);
	
	int exa[] = {201,104,138,200,111,7,6,15,7,198,235,134,110,110,102,173,76,141,172,235,38,110,235,204,174,205,140,134,173,102,205,142,134,141,175};
	
	if (strlen(flag) != 0x23)
		
		puts("Wrong Flag!");
	
	for (int i = 0;i < strlen(flag);i++)
	
	{
		
		int a = flag[i] << 5 & 0xFF,b = flag[i] >> 3 & 0xFF;
		
		flag2[i] = a ^ b;
	
	}
	
	for (int i = 0;i < 35;i++)
	
	{
		
		if (flag2[i] != exa[i])
		
		{
			
			puts("Wrong Flag!");
			
			return 0;
		
		}
	
	}

puts("Correct!");

}


Share Tweet +1