隐藏IAT和字符串
隐藏IAT和字符串
0x01 IAT
IAT即导入表,它记录了我们的文件用了哪些函数。
在杀软检测恶意程序时,导入表是一个重要的检测项,比如说我们的程序调用了Virtual Alloc、
CreateThread,且VirtualAlloc的最后一个参数是0x40(即PAGE_EXECUTE_READWRITE ),那么在杀软看来,我们的程序就是一个高危文件。
我们所要做的就是隐藏我们所使用的敏感API,下面是一个小demo:
#include<stdio.h>
#include<Windows.h>
int main()
{
printf("hello world\n");
MessageBox(0, TEXT("hello world"), 0, 0);
return 0;
}
我们编译后执行,得到结果如下:
我们用dumpbin来查看我们的导入,命令如下:
dumpbin /IMPORTS demo.exe
可以看到在USER32.dll中引用了MessageBoxW函数,我们现在尝试利用自定义MessageBoxW函数来隐藏其在导出表中的出现。
首先找到函数的原型:
然后开始我们的自定义:
#include<stdio.h>
#include<Windows.h>
typedef int(WINAPI* pMessageBoxW)(
_In_opt_ HWND hWnd,
_In_opt_ LPCWSTR lpText,
_In_opt_ LPCWSTR lpCaption,
_In_ UINT uType
);
pMessageBoxW MyMessageBoxW = (pMessageBoxW)GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW");
int main()
{
printf("hello world\n");
MyMessageBoxW(0, TEXT("hello world"), 0, 0);
return 0;
}
这里我们定义好函数之后,使用GetProcAddress将对应dll中的对应函数的地址拿到,然后给我们自己定义的函数,从而达到隐藏的目的。
GetProcAddress的定义如下:
GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
第一个参数代表句柄,第二个参数代表函数名称。
下面看看隐藏的效果:
现在看不到我们的MessageBoxW了。
当然,这里还是会出现我们的GetProcAddress等等函数,我们也可以尝试使用自实现getprocaddress或者peb的方式来实现。
我们在自己编写shellcode时也会用到上面两种情况。
0x02 字符串
一般情况下,C/C++程序中的字符串常量会被硬编码到程序中(.data段,也就是数据段),尤其是全局变量最容易被定位到。
比如我们上例的hello world,利用strings查看我们程序里面一些字符串,命令如下
strings Hide_IAT_String.exe
当然仅仅是Hello World是没问题的,如果是我们上述隐藏IAT时的api名字,或者一些工具的参数信息,被杀软检测到就极有可能被杀。
所以我们可以自实现一些简单的加解密函数来隐藏字符串,下面是一个小demo
#include <stdio.h>
#include <Windows.h>
void reverseString(char* str) {
int length = strlen(str);
char temp;
for (int i = 0; i < length / 2; i++) {
temp = str[i];
str[i] = str[length - i - 1];
str[length - i - 1] = temp;
}
}
int main() {
char str[] = "dlrow olleh";
reverseString(str);
printf("%s",str);
}
可以看到没有找到hello相关的字符串了。
0x03参考链接
静态恶意代码逃逸(第七课) | 倾旋的博客 (payloads.online)