最近看到 一个 样本 ,里面有键盘 按键记录的功能 ,而且 实现也比较 简单,运行 记录 的效果还 不错 。主要思路如下 :
//假代码
int i=0;
for(i=0;i<0x100;i++)
{
GetKeyState(i);
//参考:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate
//如果有按键 记录,就去获取一些相关信息
//当前时间 ,活动窗口名等一起记录
}
在grok样本里面,通过hook shadow ssdt里面的相关函数:NtUserGetMessage,NtUserGetKeyState等来实现按键抓取。
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$x64 下,虚拟地址转换物理地址:
***应用层虚拟地址转换
1,在windbg中找到对应进程的DirBase
2,根据 9-9-9-9-12(pml4-pd-pt-ptd)规则,对虚拟地址进行切割,然后读取相应的内容,最后定位到物理地址。
实测例子:
进程为DbgView.exe,进程的ImageBase=0x4000000;DirBase=0x303e0000
下面查找0x400000对应的物理地址:
对虚拟地址进行切割得到偏移为0-0-2-0-0
pml4=*((qword*)0x303e000+0*8)=0xa000000`045ec867 ,取页起始地址0x45ec000
pd=*((qword*)0x45ec000+0*8)=0xa000000`5a16d867 ,取页起始地址0x5a16d000
pt=*((qword*)0x5a16d000+2*8)=0xa000000`0686f867 ,取页起始地址0x686f000
pte=*((qword*))0x686f000+0*8)=0x81000000`45b78025 ,取页起始地址0x45b78000
PhysicalAddress=0x45b78000+0=0x45b78000
可以看到物理地址和虚拟地址内容是一致的。
***内核中虚拟地址转换
内核中的虚拟地址转物理地址与应用层原理是一致的,唯一的区别在于内核中的虚拟地址都属于system。
生成随机字符串
ULONG times = 0x10;
char* GetRandString()
{
//随机因子
ULONGLONG seed = GetTickCount()+times;
//基字符串
CHAR RandString[MAX_PATH] = "aiebdcefgh\0";
CHAR* temp = NULL;
//长度随机化
int i = seed%4+strlen(RandString)-4;
RandString[i] = 0x0;
while (i>0)
{
//内容随机化
RandString[i-1] += seed % (i+2);
i--;
}
{
temp = (CHAR*)malloc(MAX_PATH);
if (temp)
{
memset(temp, 0, MAX_PATH);
strcat_s(temp,MAX_PATH, RandString);
}
}
//
times++;
return temp;
}
计算字符串哈希
//
// 计算字符串的hash
//
//注意64/32指针长度
ULONG CalStringHash(char* a1)
{
ULONG result; // rax
char v2; // cl
ULONG v3; // edx
result = (unsigned __int64)a1;
if (a1)
{
v2 = *a1;
v3 = 0;
while (v2)
{
v3 ^= 0XF673B679 * v2;
v2 = *(BYTE*)++result;
}
result = v3;
}
return result;
}