《C++ 黑客编程揭秘与防范》—第1章1.3节简单API的介绍

1.3 简单API的介绍
C++ 黑客编程揭秘与防范
下面介绍一些在黑客编程中会用到的API函数,尽量排一点简单易用的函数,用简单的几行代码来完成一定的功能,希望大家能在这里体会到编程乐趣,不至于被大段的代码影响了自己前进的心情。

1.3.1 复制自身程序到Windows目录和系统目录下
一般的病毒木马都有这种类似的功能,完成这个功能其实并不复杂,我们来拆解思考一下实现这段代码的步骤。

复制是一个拷贝的过程。既然是拷贝,就要知道拷贝的原位置和目的位置。也就是整个过程其实分3步,首先要得到自身程序所在的路径,然后获得Windows目录和系统目录,最后分别拷贝自身程序到这两个目录中。这3个步骤要如何完成,下面我们来看看完成这些功能的API函数。

获得自身程序所在路径的API函数的定义:

DWORD GetModuleFileName(
 HMODULE hModule,     // handle to module
 LPTSTR lpFilename,    // file name of module
 DWORD nSize       // size of buffer
);

该函数有3个参数,分别如下。

(1)hModule:该参数在获得自身程序时使用为NULL。

(2)lpFilename:该参数指定一个字符型的缓冲区,用于保存程序自身所在的路径。

(3)nSize:该参数指定缓冲区的大小。

获得Windows目录的API函数的定义:

UINT GetWindowsDirectory(
 LPTSTR lpBuffer,  // buffer for Windows directory
 UINT uSize     // size of directory buffer
);

该函数有两个参数,分别如下。

(1)lpBuffer:该参数指定一个字符型的缓冲区,用于保存Windows目录的路径。

(2)uSize:该参数指定缓冲区的大小。

获得系统目录的API函数的定义:

UINT GetSystemDirectory(
 LPTSTR lpBuffer,    // buffer for system directory
 UINT uSize     // size of directory buffer
);

该函数有两个参数,分别如下。

(1)lpBuffer:该参数指定一个字符型的缓冲区,用于保存系统目录的路径。

(2)uSize:该参数指定缓冲区的大小。

拷贝文件的API函数的定义:

BOOL CopyFile(
 LPCTSTR lpExistingFileName,   // name of an existing file
 LPCTSTR lpNewFileName,    // name of new file
 BOOL bFailIfExists      // operation if file exists
);

该函数有3个参数,分别如下。

(1)lpExistingFileName:该参数指向一个已存在文件的路径,即原文件路径。

(2)lpNewFileName:该参数指向一个新的文件的位置,即欲拷贝到的文件的目的路径。

(3)bFailIfExists:该参数是一个布尔型参数,如果参数为TRUE,若目的文件已存在则返回,复制失败;如果参数为FALSE,若目的文件已存在则强行覆盖原有的文件。

需要使用的API函数已经介绍完了,下面就来真正完成这个复制自身程序到Windows目录和系统目录下的程序,代码如下:

void CopySelf()
{
  // 保存自身程序的路径
  char szSelfName[MAX_PATH] = { 0 };
  // 保存Windows目录的路径
  char szWindowsPath[MAX_PATH] = { 0 };
  // 保存系统目录的路径
  char szSystemPath[MAX_PATH] = { 0 };
  // 临时路径变量
  char szTmpPath[MAX_PATH] = { 0 };
  GetModuleFileName(NULL, szSelfName, MAX_PATH);
  GetWindowsDirectory(szWindowsPath, MAX_PATH);
  GetSystemDirectory(szSystemPath, MAX_PATH);
  strcat(szWindowsPath, "\\backdoor.exe");
  strcat(szSystemPath, "\\backdoor.exe");
  CopyFile(szSelfName, szWindowsPath, FALSE);
  CopyFile(szSelfName, szSystemPath, FALSE);
}

该函数需要包含Windows.h这个头文件,也就是在该段程序的最开始处加一句:

include

1.3.2 获得系统的相关信息
了解一个系统相关信息也是一项比较重要的内容,强大的扫描软件Nmap在对目标主机进行扫描时,也能对目标主机的系统等信息进行识别,真的是很强大。这里简单地获取一些与系统相关的信息,主要获取的内容有操作系统的版本、操作系统的名字及当前登录的用户名称。接下来逐个介绍这些API函数。

(1)获取操作系统版本

代码如下:

BOOL GetVersionEx(
 LPOSVERSIONINFO lpVersionInfo // version information
);

该函数就一个参数,这个参数是指向一个OSVERSIONINFO结构的指针。看一下OSVERSIONINFO这个结构体。

typedef struct _OSVERSIONINFO{
   DWORD dwOSVersionInfoSize;   // 结构体大小
   DWORD dwMajorVersion;      // 主版本号
   DWORD dwMinorVersion;      // 次版本号
   DWORD dwBuildNumber;
   DWORD dwPlatformId;       // 平台ID
   TCHAR szCSDVersion[ 128 ];   // 补丁包
} OSVERSIONINFO;

dwPlatformId的取值有3个,而现在主要使用一个,即VER_PLATFORM_WIN32_NT。

(2)获取计算机名称

代码如下:

BOOL GetComputerName(
 LPTSTR lpBuffer, // computer name
 LPDWORD lpnSize  // size of name buffer
);

该函数有两个参数,介绍如下。

① lpBuffer:保存计算机名称缓冲区。

② lpnSize:保存缓冲区的长度,该参数是一个输入/输出参数。

(3)获取当前用户名称

代码如下:

BOOL GetUserName(
 LPTSTR lpBuffer, // name buffer
 LPDWORD nSize   // size of name buffer
);

该函数有两个参数,介绍如下。

① lpBuffer:保存当前用户名称的缓冲区。

② nSize:保存缓冲区的长度,该参数是一个输入/输出参数。

我们封装一个简单的函数来获取系统的这3个信息,代码如下:

void GetSysInfo()
{
  char szComputerName[MAXBYTE] = { 0 };
  char szUserName[MAXBYTE] = { 0 };
  unsigned long nSize = MAXBYTE;
  OSVERSIONINFO OsVer;
  OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  GetVersionEx(&OsVer);
  if ( OsVer.dwPlatformId == VER_PLATFORM_WIN32_NT )
  {
    if ( OsVer.dwMajorVersion == 5 && OsVer.dwMinorVersion == 1 )
    {
      printf("Windows XP %s \r\n", OsVer.szCSDVersion);
    }
    else if ( OsVer.dwMajorVersion == 5 && OsVer.dwMinorVersion == 0)
    {
      printf("Windows 2K \r\n");
    }
  }
  else
  {
    printf("Ohter System \r\n");
  }
  GetComputerName(szComputerName, &nSize);
  printf("Computer Name is %s \r\n", szComputerName);
  nSize = MAXBYTE;
  GetUserName(szUserName, &nSize);
  printf("User Name is %s \r\n", szUserName);
}

将代码进行编译连接并运行,其执行结果如图1-13所示。

这个程序完成了我们想要的功能,对于编程的部分就介绍到这里。下面介绍Debug和Release方面的内容。

1.3.3 Debug和Release的编译方式
关于获取系统信息的程序,我们编写完成了,也编译连接并运行过了。找到刚才编译的程序,查看一下它的文件大小,如图1-14所示。

从图1-14中可以看出,该程序竟然有153KB大小。是不是很惊人?我们一共写了不过十几行代码,但是却生成了如此大体积的程序,这是为什么呢?因为代码默认编译连接是Debug版本的,如图1-15所示。

从图1-15中可以看出,我们的代码是由Debug方式编译的。Debug被称为调试版本,在这种方式的编译下,可执行程序中会附带很多和调试相关的数据或代码,而且不做任何的优化,以此为开发人员提供大量的调试信息,从而方便了程序的调试工作。除了Debug方式编译以外,还有一种方式是Release方式编译,单击“Win32 Debug”右边的下拉箭头可以选择“Win32 Release”,如图1-16所示。

Release方式被称作发布版本,是为最终用户使用的,这种方式对代码做了大量的优化工作,不再包含与调试相关的信息,从而使程序的运行效率更高,体积更小,如图1-17所示。

从图1-17可以看出,两个程序的文件大小发生了截然不同的变化。因此,当我们自己写程序调试时,应该使用调试版,以方便我们对程序进行调试。当我们的程序已经调试完毕,那么可以使用发布版来与大家进行交流。

1.3.4 查看函数定义
很多时候,我们都需要查看函数的定义,而函数的定义都在SDK的头文件中。虽然从MSDN中也能找到函数的定义,但是还是有略微的不同,而且对于查找自定义函数的函数定义也是很方便的。

回到我们的代码当中,随便选中一个API函数,比如GetComputerName()这个函数。加入要查看该函数的定义应该如何查看呢?我们在GetComputerName()这个函数上单击鼠标右键,在弹出的快捷菜单上选择“Go To Definition Of GetComputerName”(到GetComputerName函数的定义处)命令,如图1-18所示。

当选择“Go To Definition Of GetComputerName”命令以后,会来到“Winbase.h”头文件中的GetComputerName()函数的定义处,如图1-19和图1-20所示。

图1-19 “Winbase.h”头文件

从图1-20中可以看出,GetComputerName是一个宏,其对应的函数为GetComputerNameA()。关于GetComputerName()和GetComputerNameA(),包括可以看到的GetComputerNameW(),我们都不进行介绍。通过图1-20的函数定义和前面介绍这个函数的定义来比较一下,可以看到,头文件中的定义比MSDN中的定义对于函数的描述更加详细,比如WINAPI表示函数的调用方式。

除了“Go To Definition Of GetComputerName”以外,还有一个“Go To Reference To GetComputerName”,这个是查看何处引用了函数。大家可以自行进行练习。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2024-09-28 11:20:17

《C++ 黑客编程揭秘与防范》—第1章1.3节简单API的介绍的相关文章

《C++ 黑客编程揭秘与防范(第2版)》—第6章6.4节PE相关编程实例

6.4 PE相关编程实例 C++ 黑客编程揭秘与防范(第2版) 前面讲的都是概念性的知识,本节主要编写一些关于PE文件结构的程序代码,以帮助读者加强对PE结构的了解. 6.4.1 PE查看器 写PE查看器并不是件复杂的事情,只要按照PE结构一步一步地解析就可以了.下面简单地解析其中几个字段内容,显示一下节表的信息,其余的内容只要稍作修改即可.PE查看器的界面如图6-26所示. PE查看器的界面按照图6-26所示的设置,不过这个可以按照个人的偏好进行布局设置.编写该PE查看器的步骤为打开文件并创建

《C++ 黑客编程揭秘与防范》—第1章1.1节编程语言和开发环境的选择

第1章 黑客编程入门 C++ 黑客编程揭秘与防范 你是否曾经在用别人开发的工具尝试"入侵",你是否希望开发出自己的黑器--相信很多人有着这种近似相同的经历.本章将简单介绍黑客编程及工具开发.如果你是初学编程,如果你从来没有接触过黑客软件的开发,如果你急于想了解黑客编程方面的知识--那么就请继续往下阅读. 1.1 编程语言和开发环境的选择 C++ 黑客编程揭秘与防范 初学者刚开始学习编程语言最头疼的问题就是如何选择编程语言及合适的开发环境,下面就来具体介绍一下. 有人认为学编程就是学编程

《C++ 黑客编程揭秘与防范》——1.1 编程语言和开发环境的选择

1.1 编程语言和开发环境的选择 C++ 黑客编程揭秘与防范 初学者刚开始学习编程语言最头疼的问题就是如何选择编程语言及合适的开发环境,下面就来具体介绍一下. 有人认为学编程就是学编程语言,而VC.VB这样的开发环境只是工具,不需要学.这个想法是错误的,因为开发环境提供了很多开发工具,如VC这个集成开发环境就提供了与之对应的PSDK.MFC等.除了语言以外,要开发特定的软件是需要开发包和开发工具支持的.况且,编程语言也是一种工具,用于和计算机进行交流的工具.所以我们既要学习编程语言,也要学习开发

《C++ 黑客编程揭秘与防范》——1.3 简单API的介绍

1.3 简单API的介绍 C++ 黑客编程揭秘与防范 下面介绍一些在黑客编程中会用到的API函数,尽量排一点简单易用的函数,用简单的几行代码来完成一定的功能,希望大家能在这里体会到编程乐趣,不至于被大段的代码影响了自己前进的心情. 1.3.1 复制自身程序到Windows目录和系统目录下 一般的病毒木马都有这种类似的功能,完成这个功能其实并不复杂,我们来拆解思考一下实现这段代码的步骤. 复制是一个拷贝的过程.既然是拷贝,就要知道拷贝的原位置和目的位置.也就是整个过程其实分3步,首先要得到自身程序

《C++ 黑客编程揭秘与防范》——1.2 应用程序的调试

1.2 应用程序的调试 C++ 黑客编程揭秘与防范 在开发程序的过程中,除了编码以外还需要对程序进行调试,当编写的程序出现问题后,就要对程序进行调试.调试不是仅使用一个printf()或MessageBox()进行简单的输出来观察某个函数的返回值(虽然在调试的时候的确是对返回值观察较多),也不是对某个变量.某一时间的具体值的输出.调试是有专业的调试分析工具的,VC6不但提供代码编辑.代码编译.编译连接等功能,还提供了一个非常好用的调试工具.在编写完代码后,如果程序输出的结果是未知的,或者是没有预

《C++ 黑客编程揭秘与防范(第2版)》——6.1 PE文件结构

6.1 PE文件结构 C++ 黑客编程揭秘与防范(第2版) PE(Portable Executable),即可移植的执行体.在Windows平台(包括Win 9x.Win NT.Win CE--)下,所有的可执行文件(包括EXE文件.DLL文件.SYS文件.OCX文件.COM文件--)均使用PE文件结构.这些使用PE文件结构的可执行文件也称为PE文件. 普通的程序员也许没有必要掌握PE文件结构,因为其大多是开发服务性.决策性.辅助性的软件,比如MIS.HIS.CRM等软件.但是对于学习黑客编程

《C++ 黑客编程揭秘与防范(第2版)》—第6章6.3节PE结构的3种地址

6.3 PE结构的3种地址 C++ 黑客编程揭秘与防范(第2版) 在上一章中用OD调试器调试程序时看到的地址与本章使用C32Asm以十六进制形式查看程序时的地址形式有所差异.程序在内存中与在文件中有着不同的地址形式,而且PE相关的地址不只有这两种形式.与PE结构相关的地址形式有3种,且这3种地址形式可以进行转换. 6.3.1 与PE结构相关的3种地址 与PE结构相关的3种地址是VA(虚拟地址).RVA(相对虚拟地址)和FileOffset(文件偏移地址). VA(虚拟地址):PE文件映射到内存后

《C++ 黑客编程揭秘与防范(第2版)》——6.3 PE结构的3种地址

6.3 PE结构的3种地址 C++ 黑客编程揭秘与防范(第2版) 在上一章中用OD调试器调试程序时看到的地址与本章使用C32Asm以十六进制形式查看程序时的地址形式有所差异.程序在内存中与在文件中有着不同的地址形式,而且PE相关的地址不只有这两种形式.与PE结构相关的地址形式有3种,且这3种地址形式可以进行转换. 6.3.1 与PE结构相关的3种地址 与PE结构相关的3种地址是VA(虚拟地址).RVA(相对虚拟地址)和FileOffset(文件偏移地址). VA(虚拟地址):PE文件映射到内存后

《C++ 黑客编程揭秘与防范(第2版)》——第6章 加密与解密

第6章 加密与解密 C++ 黑客编程揭秘与防范(第2版) 本章介绍的是关于加密与解密的知识,但是从整篇的内容上来看很难找到具体的加密与解密的知识.本章主要介绍PE结构.调试API函数等相关的内容.加密与解密,简单来说,主要就是逆向与调试.这些知识在前面的章节已经介绍过了,而掌握本章的知识以后会提高逆向与调试的能力. PE结构是Windows下可执行文件的标准结构,可执行文件的装载.内存分布.执行等都依赖于PE结构,而在逆向分析软件时,为了有目的.更高效地了解程序,必须掌握PE结构.要掌握反病毒.