0x1 实现反调试的思路

主角API

1
GetStartupInfo (STARTUPINFO)  使用此API可以在进程启动的时候获取启动信息结构体

  1.我们的程序中调用Getstartupinfo API来获取启动时的启动信息。

  2.判断启动信息结构体的值,是否是我们预期的,如果非预期则调用 ExitProcess结束进程。

  3.如果是调试器启动我们的程序.那么启动信息结构体的信息肯定是不同的。

0x2 实验

先呈上代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main()
{
    STARTUPINFO si;
    si.cb = sizeof(si);//包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO)

    GetStartupInfo(&si);
    if (si.dwFlags != 1)
    {
      printf("si.dwFlags:%lu\r\n",si.dwFlags);
      printf("Debugger found!\r\n");
      ExitProcess(0);
    }
    printf("si.dwFlags:%lu\r\n",si.dwFlags);
    printf("Debugger not found!\r\n");
    system("pause");
    return 0;
}

调试器启动:

桌面管理器启动:

0x3最后附上STARTUPINFO结构体的信息

来源

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _STARTUPINFO 
{ 
	DWORD cb;			 	 //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO) 
    PSTR lpReserved;		 //保留。必须初始化为NULL
    PSTR lpDesktop;			 //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联 
    PSTR lpTitle;			 //用于设定控制台窗口的名称。如果lpTitle是NULL,则可执行文件的名字将用作窗口名.This parameter must be NULL for GUI or console processes that do not create a new console window.
    DWORD dwX;				 //用于设定应用程序窗口相对屏幕左上角位置的x 坐标(以像素为单位)。 
    DWORD dwY;				 //对于GUI processes用CW_USEDEFAULT作为CreateWindow的x、y参数,创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员用于指明相对控制台窗口的左上角的位置
    DWORD dwXSize;			 //用于设定应用程序窗口的宽度(以像素为单位)
    DWORD dwYSize;			 //子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth、nHeight参数来创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度 
    DWORD dwXCountChars;	 //用于设定子应用程序的控制台窗口的宽度(屏幕显示的字节列)和高度(字节行)(以字符为单位) 
    DWORD dwYCountChars; 
    DWORD dwFillAttribute;   //用于设定子应用程序的控制台窗口使用的文本和背景颜色 
    DWORD dwFlags;           //请参见下一段和表4-7 的说明 
    WORD wShowWindow;        //用于设定如果子应用程序初次调用的ShowWindow 将SW_*作为nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符,除了SW_SHOWDEFAULT. 
    WORD cbReserved2;        //保留。必须被初始化为0 
    PBYTE lpReserved2;       //保留。必须被初始化为NULL
    HANDLE hStdInput;        //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存 
    HANDLE hStdOutput; 
    HANDLE hStdError; 
} STARTUPINFO, *LPSTARTUPINFO;

表4-7 dwFlags 使用标志及含义

1
2
3
4
5
6
7
STARTF_USESIZE						//使用dwXSize 和dwYSize 成员 
STARTF_USESHOWWINDOW				//使用wShowWindow 成员 
STARTF_USEPOSITION					//使用dwX 和dwY 成员 
STARTF_USECOUNTCHARS                //使用dwXCountChars 和dwYCount Chars 成员 
STARTF_USEFILLATTRIBUTE				//使用dwFillAttribute 成员 
STARTF_USESTDHANDLES				//使用hStdInput 、hStdOutput 和hStdError 成员 
STARTF_RUN_FULLSCREEN				//强制在x86 计算机上运行的控制台应用程序以全屏幕方式启动运行