首页
社区
课程
招聘
[原创][第三阶段]看雪论坛.腾讯公司2008软件安全技术竞赛
发表于: 2008-10-31 19:47 3300

[原创][第三阶段]看雪论坛.腾讯公司2008软件安全技术竞赛

2008-10-31 19:47
3300
1,简单描述一下该木马:
   运行后,枚举进程获取进程快照、遍历查找my.exe.Client.exe.woool.dat.woool88.dat.xy2.exe.game.exe.SO2Game.exe.SO2GameFree.exe.FSOnline2.exe.gameclient.exe.elementclient.exe.asktao.mod.Wow.exe.ZeroOnline.exe.Bo.exe.Conquer.exe.soul.exe.TheWarlords.exe.china_login.mpr.blueskyclient_r.exe.xy3.exe.QQLogin.exe.DNF.exe.gc12.exe.hugemanclient.exe.HX2Game.exe.QQhxgame.exe.tw2.exe.QQSG.exe.QQFFO.exe.zhengtu.dat.mir.dat.mir2.dat.tty3d.exe.metin2.bin.AClient.exe.gamefree.exe..HBQQXX.dll........多款网游客户端进程,找到进程则结束该进程;
   查找类名为"AskTao"的窗体,找到该窗体后向该窗体发送消息;
   查注册表,看是否安装360,如果装了360,就修改360的Software\\360Safe\\safemon下的ARPAccess,IEProtAcces,ExecAccess,LeakShowed,MonAccess,NoNotiLeak,NoNotiNews,SiteAccess,UDiskAccess,weeken键值,恶意关闭360的保护功能;
   从a.exe资源里分别释放HBKernel32.sys,HBQQXX.dll,System.exe三个文件:
   HBKernel32.sys 木马的驱动保护,释放到 %System32%\drivers\HBKernel32.sys.每次启动建立一个线程,调用一次ZwOpenFile 打开HBKernel32.sys文件,并且不关闭它,这样就给HBKernel32.sys下了个二重保护,这里稍后讲解,循环扫描需要保护的注册表,Software\\Microsoft\\Windows\\CurrentVersion\\Run HBService32,Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows AppInit_DLLs ,SYSTEM\\CurrentControlSet\\Services\\HBService32,如果被修改,就改回去,而且在循环的过程中还扫描Hook NtSetValueKey  NtOpenProcess,NtSetInFormationFile, NtCreateThread 四个地址,发现被恢复,立即还原,所以一般的恢复hook方法难以实现;
贴一段这个线程的代码,将就看下吧:
NTSTATUS __stdcall StartRoutine(PVOID a1)
{
  signed int v1; // ecx@1
  int *v2; // edi@1
  NTSTATUS v4; // eax@5
  int v5; // [sp+4h] [bp-168h]@1
  LARGE_INTEGER Interval; // [sp+164h] [bp-8h]@3
  HANDLE Handle; // [sp+34h] [bp-138h]@4
  const WCHAR SourceString; // [sp+64h] [bp-108h]@5
  UNICODE_STRING DestinationString; // [sp+5Ch] [bp-110h]@5
  OBJECT_ATTRIBUTES ObjectAttributes; // [sp+40h] [bp-12Ch]@5
  struct _IO_STATUS_BLOCK IoStatusBlock; // [sp+38h] [bp-134h]@5
  int v12; // [sp+1Ch] [bp-150h]@7
  int v13; // [sp+24h] [bp-148h]@9
  int v14; // [sp+20h] [bp-14Ch]@11
  int v15; // [sp+2Ch] [bp-140h]@13
  char Source2; // [sp+58h] [bp-114h]@14
  char v17; // [sp+59h] [bp-113h]@14
  char v18; // [sp+5Ah] [bp-112h]@14
  int v19; // [sp+Ch] [bp-160h]@16
  int v20; // [sp+8h] [bp-164h]@18
  int v21; // [sp+18h] [bp-154h]@23
  int v22; // [sp+14h] [bp-158h]@25
  int v23; // [sp+10h] [bp-15Ch]@27
  int v24; // [sp+30h] [bp-13Ch]@30

  v2 = &v5;
  v1 = 13;
  do
  {
    *v2 = 0;
    ++v2;
    --v1;
  }
  while ( v1 );
  Interval = (LARGE_INTEGER)-1000000i64;
  while ( !dword_13F20 )
  {
    KeDelayExecutionThread(0, 0, &Interval);
    if ( !Handle )
    {
      RtlZeroMemory(&SourceString, 256);
      sub_1160A(&SourceString, L"", byte_13A00);
      RtlInitUnicodeString(&DestinationString, &SourceString);
      ObjectAttributes.Length = 24;
      ObjectAttributes.RootDirectory = 0;
      ObjectAttributes.Attributes = 0;
      ObjectAttributes.SecurityDescriptor = 0;
      ObjectAttributes.ObjectName = &DestinationString;
      ObjectAttributes.SecurityQualityOfService = 0;
      v4 = ZwOpenFile(&Handle, 0x100001u, &ObjectAttributes, &IoStatusBlock, 0, 0x20u);   //打开HBKernel32.sys,没关闭句柄
      if ( !sub_103B0(v4) )
        Handle = 0;
    }
    s_ZwSetValueKey();//还原注册表
    if ( v12 )
    {
      if ( v13 )
      {
        if ( v14 )
        {
          if ( v15 )
          {
            sub_10D04(v15, (int)sub_120D9, &loc_12106);
          }
          else
          {
            Source2 = -62;
            v17 = 32;
            v18 = 0;
            v15 = sub_127C5(v13, 4096, v14, &Source2, 3u);
          }
        }
        else
        {
          v14 = sub_1285B();
        }
      }
      else
      {
        v13 = sub_1329B(v12);
      }
    }
    else
    {
      RtlZeroMemory(&SourceString, 256);
      sub_1160A(&SourceString, &unk_13A01, byte_13A1F);
      RtlInitUnicodeString(&DestinationString, &SourceString);
      v12 = sub_13379(&DestinationString);
    }
    if ( v19 )
    {
      if ( v20 )
      {
        if ( v5 )
        {
          sub_10D04(v5, (int)sub_1212F, &loc_12164);
        }
        else
        {
          Source2 = -62;
          v17 = 20;
          v18 = 0;
          v5 = sub_127C5(v19, 4096, v20, &Source2, 3u);
        }
      }
      else
      {
        RtlZeroMemory(&SourceString, 256);
        sub_1160A(&SourceString, &unk_1391F, byte_13953);
        RtlInitUnicodeString(&DestinationString, &SourceString);
        v20 = (int)MmGetSystemRoutineAddress(&DestinationString);
      }
    }
    else
    {
      RtlZeroMemory(&SourceString, 256);
      sub_1160A(&SourceString, &unk_138F4, byte_1391E);
      RtlInitUnicodeString(&DestinationString, &SourceString);
      v19 = (int)MmGetSystemRoutineAddress(&DestinationString);
    }
    if ( v21 )
    {
      if ( v22 )
      {
        if ( v23 )
        {
          sub_10D04(v23, (int)sub_1210B, &loc_1212A);
        }
        else
        {
          Source2 = -62;
          v17 = 16;
          v18 = 0;
          v23 = sub_127C5(v21, 4096, v22, &Source2, 3u);
        }
      }
      else
      {
        RtlZeroMemory(&SourceString, 256);
        sub_1160A(&SourceString, &unk_13971, byte_139A7);
        RtlInitUnicodeString(&DestinationString, &SourceString);
        v22 = (int)MmGetSystemRoutineAddress(&DestinationString);
      }
    }
    else
    {
      RtlZeroMemory(&SourceString, 256);
      sub_1160A(&SourceString, &unk_13954, byte_13970);
      RtlInitUnicodeString(&DestinationString, &SourceString);
      v21 = (int)MmGetSystemRoutineAddress(&DestinationString);
    }
    if ( v24 )
    {
      sub_1102B(v24, (LONG)&loc_12169, &loc_12185);
    }
    else
    {
      RtlZeroMemory(&SourceString, 256);
      sub_1160A(&SourceString, &unk_13A4B, byte_13A67);
      RtlInitUnicodeString(&DestinationString, &SourceString);
      v24 = sub_13379(&DestinationString);
    }
  }
  if ( v15 )
    sub_10ACD(v15);
  if ( v5 )
    sub_10ACD(v5);
  if ( v23 )
    sub_10ACD(v23);
  if ( v24 )
    sub_1101C(v24);
  if ( Handle )
  {
    ZwClose(Handle);
    Handle = 0;
  }
  return PsTerminateSystemThread(0);
}

    hook一个SSDT函数NtSetValueKey 三个内核代码hook NtOpenProcess,NtSetInFormationFile, NtCreateThread,NtSetValueKey 让你不能修改木马保护的注册表,NtOpenProcess和NtCreateThread让你不能结束System.exe进程 ,NtSetInFormationFile让你不能删除修改System.exe HBKernel32.sys HBQQXX.dll 三个文件
   HBQQXX.dll 全局钩子,释放到 %System32%\HBQQXX.dll 通过System.exe木马启动程序修改注册表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 下全局
  钩子.盗取游戏帐号密码
   System.exe 通过添加HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run子键HBService32系统每次启动运行Sytem.exe,向驱动发送0x22E007,0x22E00B,0x22E00F命令,与驱动通信,0x22E007是驱动第一次启动需要发送的,0x22E00B这个需要传递一个进程id,这个进程id就是驱动要保护的进程,0x22E00B配合0x22E007使用,0x22E00F这个也要传递一个BOOL型变量,为FASLE时 停止驱动删除文件保护,为TRUE时 启动驱动删除文件保护.

2.ring3下删除木马
  通过上面分析,要想删除改木马,必须突破他的驱动HBKernel32.sys保护,HBKernel32.sys通一个线程定时监控注册表,一旦有注册表被修改,立即改回来.hook了四个函数ZwSetValueKey, NtOpenProcess,NtSetInFormationFile, NtCreateThread, NtSetValueKey 让你不能修改驱动保护的注册表,NtOpenProcess和NtCreateThread让你不能结束System.exe进程 ,NtSetInFormationFile让你不能删除修改System.exe HBKernel32.sys HBQQXX.dll 三个文件,确实很牛X,不用驱动ring3很难搞定.不过经过上面分析,这个木马还是留了一手的,他要向驱动发送三个命令0x22E007,0x22E00B,0x22E00F命令,而且参数很好模拟,完全可以以牙还牙哈,
   以牙还牙,模拟0x22E00B命令发送一个伪装的进程Id给驱动,这样就可以在ring3下结束掉 System.exe进程,然后在模拟0x22E00F命令发送一个FALSE 停止驱动删除文件保护,这样可以直接删除System.exe,因为System.exe进程已经被结束,经过测试,0x22E00F不但可以删除System.exe,还可以重命名HBQQXX.dll,在适当修改下,利用模拟的0x22E00F,还可以删除HBKernel32.sys ,这里要解释下为什么需要修改,而不是像删除System.exe一样删除HBKernel32.sys,因为HBKernel32.sys文件,在驱动线程里被ZwOpenFile打开过,并且没有被关闭,这样子就造成该文件被system系统进程(注意:这里说的system系统进程不是System.exe)独占了,修改或者删除都要报错,因为他被system系统进程一直占用着,所以要删除HBKernel32.sys文件,就必须关闭HBKernel32.sys被打开的句柄,才能删除.
   ok,现在可以删除HBKernel32.sys,结束System.exe并删除,HBQQXX.dll也可以改名字,哈哈,现在就简单了吧,做了这些操作重起计算机,然后给自己程序放到run里,下次启动时因为驱动保护都不起作用了,HBQQXX.dll也被改名了(但然这里可以不用改名,直接远程释放掉dll,然后删除),完全可以直接把木马的所有文件删除,然后把注册里的东东都恢复过来,木马被干掉.

3.实现的核心代码
  这里我发一下我删除System.exe和HBKernel32.sys的代码:
删除System.exe的代码:
//清除System.exe
BOOL ClearSystem()
{
	BOOL bResult=false;
	HANDLE hDevice;    
	HANDLE hProcessHandle; 
	ULONG dwReturn;
	DWORD dwProcessID;
	DWORD dwOutBuffer;
	hDevice = NULL;
	//转移驱动保护的System.exe进程ID,然后可以在ring3结束掉System.exe
	hDevice = CreateFile("\\\\.\\slHBKernel32",
		GENERIC_READ|GENERIC_WRITE,
		0, 
		NULL,
		OPEN_EXISTING, 
		FILE_ATTRIBUTE_NORMAL, 
		NULL);
	
	if(hDevice == INVALID_HANDLE_VALUE)
	{
		printf("CreateFile 出错!\n");
		printf("重起电脑,在杀!\n");
		return bResult;
	}
	
	bResult=DeviceIoControl(hDevice,
		0x22E007,
		NULL,
		0,
		0,
		0,
		&dwReturn,NULL);
	//得到当前进程ID
	dwProcessID=GetCurrentProcessId();
	//转移木马驱动保护的进程ID
	bResult=DeviceIoControl(hDevice,
		0x22E00B,
		&dwProcessID,
		4,
		&dwOutBuffer,
		4,
		&dwReturn,NULL);
	
	//结束System.exe进程
	while(TRUE)
	{
		hProcessHandle = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,dwOutBuffer);
		if(hProcessHandle)
		{
			TerminateProcess(hProcessHandle,4);
			WaitForSingleObject(hProcessHandle,INFINITE);
			CloseHandle(hProcessHandle);			
		}
		else
		{
			printf("结束System.exe进程成功!\n");
			break;
		}
	}	

	//停止木马驱动删除文件的功能,把system.exe木马进程删除
	BOOL bStart=FALSE;
	bResult=DeviceIoControl(hDevice,
		0x22E00F,
		&bStart,
		4,
		0,
		0,
		&dwReturn,NULL);	
	char szSystemPath[MAX_PATH]={NULL};
	GetSystemDirectory(szSystemPath,MAX_PATH);
	strcat(szSystemPath,"\\System.exe");
	if (DeleteFile(szSystemPath))
	{
		bResult=TRUE;
		printf("删除%s成功!\n",szSystemPath);		
	}
	else
	{
		bResult=FALSE;
		printf("删除%s失败!\n",szSystemPath);
	}
	
	CloseHandle(hDevice);
	return bResult;
}

删除HBKernel32.sys的代码:
#define NT_SUCCESS(Status)((NTSTATUS)(Status) >= 0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)

typedef LONG  NTSTATUS;
typedef struct _IO_STATUS_BLOCK 
{
NTSTATUS Status;
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _UNICODE_STRING 
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES 
{
   ULONG Length;
   HANDLE RootDirectory;
   PUNICODE_STRING ObjectName;
   ULONG Attributes;
   PVOID SecurityDescriptor;
   PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;  

typedef struct _SYSTEM_HANDLE_INformATION {
	ULONG ProcessId;
	UCHAR ObjectTypeNumber;
	UCHAR Flags; 
	USHORT Handle;
	PVOID Object;
	ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INformATION, *PSYSTEM_HANDLE_INformATION;

typedef struct _OBJECT_NAME_INformATION {
	UNICODE_STRING Name;
} OBJECT_NAME_INformATION, *POBJECT_NAME_INformATION;

typedef NTSTATUS (CALLBACK* ZWQUERYSYSTEMINformATION)( 
													  IN  ULONG SystemInformationClass,
													  IN  OUT PVOID SystemInformation,
													  IN  ULONG SystemInformationLength,
													  OUT PULONG ReturnLength OPTIONAL);

typedef NTSTATUS (CALLBACK* ZWQUERYOBJECT)(
										   IN HANDLE ObjectHandle,
										   IN ULONG ObjectInformationClass,
										   OUT PVOID ObjectInformation,
										   IN ULONG ObjectInformationLength,
										   OUT PULONG ReturnLength OPTIONAL);
typedef NTSTATUS (WINAPI *ZWUNMAPVIEWOFSECTION)(
												IN HANDLE  ProcessHandle,
												IN PVOID  BaseAddress );
ZWQUERYSYSTEMINformATION ZwQuerySystemInformation;
ZWQUERYOBJECT ZwQueryObject;
ZWUNMAPVIEWOFSECTION ZwUnmapViewOfSection;
//得到ZwQuerySystemInformation和ZwQueryObject地址
BOOL InitNTDLL()
{
	BOOL bResult=FALSE;
	HMODULE hModule = GetModuleHandle("ntdll.dll") ;
    if (hModule == NULL)
        hModule = LoadLibrary ("ntdll.dll") ;
	if ( !hModule )
	{
		return bResult;
	}
	ZwQuerySystemInformation = 
	(ZWQUERYSYSTEMINformATION)GetProcAddress( hModule, "ZwQuerySystemInformation");

	ZwQueryObject = 
	(ZWQUERYOBJECT)GetProcAddress( hModule, "ZwQueryObject");
	
	ZwUnmapViewOfSection = 
		(ZWUNMAPVIEWOFSECTION)GetProcAddress (hModule, "ZwUnmapViewOfSection") ;
	if (ZwQuerySystemInformation!=NULL&&ZwQueryObject!=NULL&&ZwUnmapViewOfSection!=NULL)
	{
		bResult=TRUE;
	}
	return bResult;
}

//调用ZwQuerySystemInformation得到句柄表
PULONG GetHandleList()
{
	ULONG cbBuffer = 0x1000;
	PULONG pBuffer = new ULONG[cbBuffer];
	NTSTATUS Status;
	DWORD dwNumBytesRet = 0x10;
	do
	{
		Status = ZwQuerySystemInformation(
			16,
			pBuffer, 
			cbBuffer * sizeof * pBuffer, 
			&dwNumBytesRet);
		
		if (Status == STATUS_INFO_LENGTH_MISMATCH)
		{
			delete [] pBuffer;
			pBuffer = new ULONG[cbBuffer *= 2];
		}
		else if (!NT_SUCCESS(Status))
		{
			delete [] pBuffer;
			return NULL;
		}
	}
	while (Status == STATUS_INFO_LENGTH_MISMATCH);
	return pBuffer;
}

//复制Handle
HANDLE DupHandle(DWORD PId, HANDLE handle)
{
	HANDLE DupHandle;
	HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, 0, PId);
	if(hProcess == NULL)
	{
		return 0;
	}
	
	if (!DuplicateHandle(hProcess, handle, GetCurrentProcess(), 
		&DupHandle, 0, 0, DUPLICATE_SAME_ACCESS))
		DupHandle = 0;
	
	CloseHandle( hProcess );
	
	return DupHandle;
}

//关闭打开HBKernel32.sys句柄
HANDLE DeleteHandle(DWORD PId, HANDLE handle)
{
	HANDLE DupHandle;
	HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, 0, PId);
	if(hProcess == NULL)
	{
		return 0;
	}
	
	if (!DuplicateHandle(hProcess, handle, GetCurrentProcess(), 
		&DupHandle, 0, 0, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
		DupHandle = 0;
	
	CloseHandle( hProcess );
	
	return DupHandle;
}

//提升权限
void EnableDebugPriv(const char *name,bool bEnablePrivilege)
{
	HANDLE hToken; 
	TOKEN_PRIVILEGES tp; 
	LUID luid; 
	//打开进程令牌环 
	OpenProcessToken(GetCurrentProcess(), 
		TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, 
		&hToken); 
	//获得进程本地唯一ID 
	LookupPrivilegeValue(NULL,name,&luid);
	
	tp.PrivilegeCount = 1; 
	if (bEnablePrivilege)
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	else
		tp.Privileges[0].Attributes = 0;
	tp.Privileges[0].Luid = luid; 
	//调整权限 
	AdjustTokenPrivileges(hToken,0,&tp,NULL,NULL,NULL); 
	CloseHandle(hToken); 
}

//删除驱动HBKernel32.sys
BOOL DeleteHBKernel32Sys()
{
	BOOL bResutl=FALSE;	

	char namebuf[2000];
	DWORD ret;
	
	HANDLE hTmp;
	GetModuleFileName(NULL,namebuf,MAX_PATH);
	hTmp = CreateFile(namebuf,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	
	PULONG buf = GetHandleList();
	if (buf == NULL)
		return bResutl;
	
	ULONG i;
	UCHAR TypeNum;
	PSYSTEM_HANDLE_INformATION info = (PSYSTEM_HANDLE_INformATION)&buf[1];
	for (i=0; i<buf[0]; i++, info++)
	{
		if (GetCurrentProcessId() == info->ProcessId && info->Handle == (USHORT)hTmp)
			TypeNum = info->ObjectTypeNumber;
	}
	CloseHandle(hTmp);
	
	info = (PSYSTEM_HANDLE_INformATION)&buf[1];
	for (i=0; i<buf[0]; i++, info++)
	{
		if (info->ObjectTypeNumber != TypeNum)
			continue;
		HANDLE handle = DupHandle(info->ProcessId, (HANDLE)info->Handle);
		NTSTATUS status;
		POBJECT_NAME_INformATION name = (POBJECT_NAME_INformATION)namebuf;
		status = ZwQueryObject(handle, 1, namebuf, 2000, &ret);
		CloseHandle(handle);
		if (status >= 0)
		{
			wchar_t outstr[1000] = L"A:";
			if (name->Name.Length > 23 && memicmp(name->Name.Buffer, L"\\Device\\HardDiskVolume", 44) == 0)
			{
				outstr[0] = name->Name.Buffer[22] - L'1' + L'C';
				memcpy(&outstr[2], &name->Name.Buffer[23], name->Name.Length-23*2);
				outstr[name->Name.Length/2-21] = 0;
			}
			wchar_t filename[1000];
			
			GetSystemDirectoryW(filename,1000);
			
			wcscat(filename,L"\\drivers\\HBKernel32.sys");
			if (wcsicmp(outstr, filename) == 0)
			{
				handle = DeleteHandle(info->ProcessId, (HANDLE)info->Handle);
				if (handle)
				{
					CloseHandle(handle);
					while (true)
					{
						if (DeleteFileW(filename))
						{
							printf("删除%ws成功!\n",filename);
							bResutl=TRUE;
							break;
						}
						else
						{
							printf("删除%ws失败!\n",filename);
						}
						Sleep(2000);
					}					
				}				
				break;
			}
		}
		
	}
	delete [] buf;
	return bResutl;
}


注:这两个函数有先后顺序的,删除System.exe在前,HBKernel32.sys的在后.删除System.exe的代码没什么好讲的,关闭HBKernel32.sys 句柄 ,调用ZwQuerySystemInformation 得到进程所有句柄,然后找到File类型的句柄,然后通过ZwQueryObject得到路径,从路径里判断是不是HBKernel32.sys的句柄,还有这里需要提权,否则system进程进不去,

4.以前没研究过木马,写得很乱,而且有一些纯粹是猜测哈,很多不妥的地方,大牛多多指点,谢谢

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
2
基础分:90分
分析文档:10分
最终得分100分
2008-11-11 23:27
0
游客
登录 | 注册 方可回帖
返回
//