首页
论坛
课程
招聘
[基础知识] [原创][C#][有码]映像劫持简析与工具类源码
2021-2-24 05:25 3226

[基础知识] [原创][C#][有码]映像劫持简析与工具类源码

2021-2-24 05:25
3226

上次发的只有源码没有解析,想了想这样不好,还是写两句,请各位批评指正。


“映像劫持”(IFEO Debugger)是注册表中IFEO(Image File Execution Options)的一个功能,用一句话描述如下:

[ 当一个被映像劫持的程序将被启动时,Windows不会启动这个程序,而是启动它的劫持者程序。 ]


也就是把启动程序的任务交给劫持者。至于要不要启动、怎么启动、启动前后的准备和收尾工作都交给劫持者完成,Windows启动劫持者之后就撒手不管了。而被劫持的程序的名称和命令行参数会一起作为劫持者的命令行参数,这样一个劫持调试器就能劫持多个程序,也能对命令行做一些处理。


映像劫持的优点是当一个程序需要被调试、或作一些启动前后的准备/收尾工作才能正常运行时,用户不必关心调试器(对用户来说是透明的),而只需要照常启动原来的程序即可,非常方便。但是这项技术很容易被滥用,比如我劫持一大堆程序,不知情的用户正常使用时我就可以悄悄的启动去干坏事。当然也可以劫持系统组件、或者根本不启动被调试的程序,坏得很哦。


映像劫持是IFEO众多功能中最先被运行的一个,也是最风评被害的一个。IFEO是用于做一些启动前的准备工作的,这样可以让远古程序也能兼容新版系统。以下是编写的一个C#映像劫持工具类,无论是ghs(干坏事)还是防止别人干坏事都可以用。其原理不过是封装了简单的注册表增删改查而已。

    /// <summary>
    /// 映像劫持工具类.
    /// </summary>
    public static class ImageHijack
    {
        public const string IFEO_LOCATION = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options";

        /// <summary>
        /// 创建或修改一个程序的映像劫持调试器. 请在管理员权限下运行.
        /// </summary>
        /// <param name="targetName">目标程序名.</param>
        /// <param name="debuggerName">调试器程序名.</param>
        /// <returns>创建成功返回true, 失败或发生错误返回false.</returns>
        public static bool CreateImageHijack(string targetName, string debuggerName)
        {
            int error = RegCreateKeyEx
            (
                new IntPtr(HKEY_LOCAL_MACHINE),
                IFEO_LOCATION + "\\" + targetName,
                0,
                null,
                REG_OPTION_NON_VOLATILE,
                (int)RegSAM.AllAccess,
                (IntPtr)null,
                out IntPtr hKey,
                out _
            );
            if (error != ERROR_SUCCESS) return false;
            error = RegSetValueExA
            (
                hKey,
                "Debugger", 
                0, 
                (uint)RegValueType.REG_SZ, 
                System.Text.Encoding.Default.GetBytes(debuggerName + "\0"), 
                (uint)debuggerName.Length
            );
            _ = RegCloseKey(hKey);
            if (error != ERROR_SUCCESS) return false;
            return true;
        }
        /// <summary>
        /// 查找程序的映像劫持调试器. 请在管理员权限下运行.
        /// </summary>
        /// <param name="targetName">目标程序名</param>
        /// <param name="debuggerName">返回的调试器程序名. 不存在时返回"".</param>
        /// <returns>映像劫持存在返回true, 不存在或发生错误返回false.</returns>
        public static bool GetImageHijackDebugger(string targetName, out string debuggerName)
        {
            debuggerName = "";
            System.Text.StringBuilder lpData = new System.Text.StringBuilder(1024);
            uint lpcbData = (uint)lpData.Capacity;
            IntPtr pHK;
            int error = RegOpenKeyEx
            (
                new IntPtr(HKEY_LOCAL_MACHINE),
                IFEO_LOCATION + "\\" + targetName,
                0,
                (int)RegSAM.AllAccess,
                out pHK
            );
            if (error != ERROR_SUCCESS) return false;
            error = RegQueryValueEx
            (
                pHK,
                "Debugger",
                0,
                out uint lpType,
                lpData,
                ref lpcbData
            );
            _ = RegCloseKey(pHK);
            if (error != ERROR_SUCCESS || lpType != (int)RegValueType.REG_SZ) return false;
            debuggerName = lpData.ToString().Trim();
            return true;
        }
        /// <summary>
        /// 获取所有被映像劫持的程序名和对应的调试器. 请在管理员权限下运行.
        /// </summary>
        /// <param name="result">返回的结果字典. 没有结果或出错则返回0个元素的字典. 被劫持的程序名作为Key, 调试器程序名作为Value.</param>
        /// <returns>返回被映像劫持的程序数量. 没有结果返回0, 出错返回-1.</returns>
        public static int GetEveryImageHijackDebugger(out System.Collections.Generic.Dictionary<string, string> result)
        {
            result = new System.Collections.Generic.Dictionary<string, string>();
            int error = RegOpenKeyEx
            (
                new IntPtr(HKEY_LOCAL_MACHINE),
                IFEO_LOCATION,
                0,
                (int)RegSAM.AllAccess,
                out IntPtr pHK
            );
            if (error != ERROR_SUCCESS) return -1;
            for (int i = 0; i <= int.MaxValue; ++i)
            {
                System.Text.StringBuilder lpName = new System.Text.StringBuilder(1024);
                System.Text.StringBuilder lpClass = new System.Text.StringBuilder(1024);
                PInvoke.Struct.FILETIME lpftLastEriteTime = new PInvoke.Struct.FILETIME();
                int lpcbName = lpName.Capacity;
                int lpcbClass = lpClass.Capacity;
                error = RegEnumKeyEx
                (
                    pHK,
                    i,
                    lpName,
                    ref lpcbName,
                    0,
                    lpClass,
                    ref lpcbClass,
                    lpftLastEriteTime
                );
                if (error != ERROR_SUCCESS)
                {
                    break;
                }
                string targetName = lpName.ToString().Trim();
                bool find = GetImageHijackDebugger(targetName, out string debuggerName);
                if (find)
                {
                    result.Add(targetName, debuggerName);
                }
            }
            _ = RegCloseKey(pHK);
            return result.Count;
        }
        /// <summary>
        /// 删除一个程序的映像劫持调试器. 请在管理员权限下运行.
        /// </summary>
        /// <param name="targetName">目标程序名</param>
        /// <returns>删除成功返回true, 失败, 未被劫持或发生错误返回false.</returns>
        public static bool DeleteImageHijack(string targetName)
        {
            IntPtr pHK;
            int error = RegOpenKeyEx
            (
                new IntPtr(HKEY_LOCAL_MACHINE),
                IFEO_LOCATION + "\\" + targetName,
                0,
                (int)RegSAM.AllAccess,
                out pHK
            );
            if (error != ERROR_SUCCESS) return false;
            error = RegDeleteValue(pHK, "Debugger");
            _ = RegCloseKey(pHK);
            if (error != ERROR_SUCCESS) return false;
            return true;
        }
    }

代码是从我的工具类库“Iris Hammer Core”版本20中截取的,所以如果看见奇怪的东西请告诉我我来补充他们的定义。以下是本地调用的函数和常量。来源于网络的部分恕不标注致谢。

// CONST

public const int HKEY_LOCAL_MACHINE = unchecked ((int)0x80000002);
public const int REG_OPTION_NON_VOLATILE = 1;
[System.Flags] public enum RegSAM
{
    QueryValue = 0x0001,
    SetValue = 0x0002,
    CreateSubKey = 0x0004,
    EnumerateSubKeys = 0x0008,
    Notify = 0x0010,
    CreateLink = 0x0020,
    WOW64_32Key = 0x0200,
    WOW64_64Key = 0x0100,
    WOW64_Res = 0x0300,
    Read = 0x00020019,
    Write = 0x00020006,
    Execute = 0x00020019,
    AllAccess = 0x000f003f
}
public enum RegValueType
{
    REG_NONE,
    REG_SZ,
    REG_EXPAND_SZ,
    REG_BINARY,
    REG_DWORD,
    REG_DWORD_LITTLE_ENDIAN,
    REG_DWORD_BIG_ENDIAN,
    REG_LINK,
    REG_MULTI_SZ,
    REG_RESOURCE_LIST,
    REG_FULL_RESOURCE_DESCRIPTOR,
    REG_RESOURCE_REQUIREMENTS_LIST,
    REG_QWORD,
    REG_QWORD_LITTLE_ENDIAN
}
public const int ERROR_SUCCESS = 0;

// WinAPI

[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegCreateKeyEx(IntPtr hKey, string lpSubKey, int reserved, string type, int dwOptions, int REGSAM, IntPtr lpSecurityAttributes, out IntPtr phkResult, out int lpdwDisposition);
[DllImport("Advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern int RegSetValueExA(IntPtr hKey, string lpValueName, uint unReserved, uint unType, byte[] lpData, uint dataCount);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegOpenKeyEx(IntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out IntPtr phkResult);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved, out uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegEnumKeyEx(IntPtr hKey, int dwIndex, System.Text.StringBuilder lpName, ref int lpcbName, int lpReserved, System.Text.StringBuilder lpClass, ref int lpcbClass, FILETIME lpftLastWriteTime);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegDeleteValue(IntPtr hKey, string lpValueName);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegCloseKey(IntPtr hKey);

// STRUCT

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct FILETIME
{
    int dwLowDateTime;
    int dwHighDateTime;
}

这里的敏感字符串很显眼,可以参考这个帖子进行简单加密:[原创][C#][有码]对程序中的敏感明文字符串进行简单的加密

我还想把类库里面的其他东西发出来,可是那样就太长了写不下(费马行为x

所以我还得想想怎么办。


萌新发帖无技术求轻拍。我不生产知识,我只是个搬运工。

代码风格很差,望各位大佬教育。


[看雪官方培训] Unicorn Trace还原Ollvm算法!《安卓高级研修班》2021年6月班开始招生!!

最后于 2021-3-13 02:05 被星雪鸢尾编辑 ,原因: 增加解析,补充结构定义,超链接到相关帖子
收藏
点赞1
打赏
分享
最新回复 (3)
雪    币: 355
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:40 )
在线值:
发帖
回帖
粉丝
Victorgg 活跃值 2021-2-25 14:56
2
0
感谢分享!
雪    币: 371
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
星雪鸢尾 活跃值 2021-2-25 15:09
3
0
Victorgg 感谢分享!
不敢不敢,我只是个搬运工
雪    币: 371
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
星雪鸢尾 活跃值 2021-3-6 08:44
4
0
好想转正哦(小声
游客
登录 | 注册 方可回帖
返回