Skip to content

Commit d4cfd26

Browse files
committed
.
1 parent ba7ba34 commit d4cfd26

File tree

7 files changed

+1317
-0
lines changed

7 files changed

+1317
-0
lines changed

ex/lib/ex.ex

+125
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,128 @@ defmodule Ex do
1616
:world
1717
end
1818
end
19+
20+
defmodule Snip do
21+
def trim_elixir(mod) when is_list(mod) do
22+
Enum.map(mod, &String.to_atom(String.trim("#{&1}", "Elixir.")))
23+
end
24+
25+
def trim_elixir(mod) do
26+
String.to_atom(String.trim("#{mod}", "Elixir."))
27+
end
28+
29+
defmodule Locallink do
30+
def route(_, source, dest, dest_port) do
31+
IO.inspect({:route, source, dest, dest_port})
32+
33+
case {source, dest, dest_port} do
34+
# {_, _, 80} -> %{uplink: nil, module: Mitm.Hexdump} #master server
35+
# master server
36+
{_, _, 33004} -> %{uplink: nil, module: Mitm.Lobby}
37+
# game server
38+
{_, _, 35001} -> %{uplink: nil, module: Mitm.Game}
39+
_ -> %{module: Raw, uplink: nil}
40+
end
41+
end
42+
end
43+
44+
defmodule S5link do
45+
def route(_, source, dest, dest_port) do
46+
if dest_port != 443 do
47+
IO.inspect({:route, source, dest, dest_port})
48+
end
49+
50+
case {source, dest, dest_port} do
51+
# master server
52+
{_, _, p} when p in [30204, 20000, 10000, 4000] ->
53+
%{uplink: nil, module: Mitm.Proto}
54+
55+
# {_, _, _} ->
56+
# proxy = %{
57+
# host: "http://49.0.246.161:3344",
58+
# ip: "49.0.246.161",
59+
# password: "aa1111",
60+
# port: 3344,
61+
# type: :socks5,
62+
# username: "aa1111"
63+
# }
64+
#
65+
# %{uplink: proxy, module: Raw }
66+
67+
_ ->
68+
%{module: Raw, uplink: nil}
69+
end
70+
end
71+
end
72+
73+
def locallink(router \\ Snip.S5link) do
74+
specs = [
75+
%{port: 31332, router: router},
76+
%{port: 9021, router: router, listener_type: :sock5}
77+
]
78+
79+
# DNS.Server2Sup.start_link(%{
80+
# static_names: %{"live-dl.nightcrows.com" => {172, 0, 0, 1}},
81+
# uplink_server: "1.1.1.1",
82+
# proxy: {"127.0.0.1", 1080}
83+
# })
84+
85+
# {:ok, _} = DynamicSupervisor.start_child(NC.Supervisor, %{
86+
# id: MitmConns,
87+
# start: {Mitme.Acceptor.Supervisor, :start_link, [[locallink]]}})
88+
{:ok, _} = Mitme.Acceptor.Supervisor.start_link(specs)
89+
end
90+
91+
def link_s5(specs \\ %{port: 9021, router: Snip.S5link, listener_type: :sock5}) do
92+
# {:ok, _} = DynamicSupervisor.start_child(NC.Supervisor, %{
93+
# id: MitmConns,
94+
# start: {Mitme.Acceptor.Supervisor, :start_link, [[locallink]]}})
95+
96+
# DNS.Server2Sup.start_link(
97+
# %{
98+
# static_names: %{"live-dl.nightcrows.co.kr" => "172.0.0.1"},
99+
# uplink_server: "1.1.1.1",
100+
# proxy: {"192.168.2.153", 1080}
101+
# },
102+
# max_restarts: 99999999999
103+
# )
104+
105+
{:ok, _} = Mitme.Acceptor.Supervisor.start_link([specs])
106+
end
107+
end
108+
109+
defmodule Mitm.Hexdump2 do
110+
use GenServer
111+
112+
def init(_) do
113+
{:ok, %{}}
114+
end
115+
116+
def connect_addr(address, port) do
117+
IO.inspect({:connect, address, port})
118+
{address, port}
119+
end
120+
121+
def on_connect(flow = %{dest: socket}) do
122+
:inet.setopts(socket, [{:active, true}, :binary])
123+
Map.merge(flow, %{start_time: :os.system_time(1)})
124+
end
125+
126+
def on_close(socket, state) do
127+
state
128+
end
129+
130+
# server conn
131+
def proc_packet(:server, bin, s) do
132+
IO.puts("<- #{s.dest_addr} #{s.dest_port}")
133+
IO.puts(Hexdump.to_string(bin))
134+
{:send, bin, s}
135+
end
136+
137+
# client conn
138+
def proc_packet(:client, bin, s) do
139+
IO.puts("-> #{s.dest_addr} #{s.dest_port}")
140+
IO.puts(Hexdump.to_string(bin))
141+
{:send, bin, s}
142+
end
143+
end

ex/lib/mitm_proto.ex

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
defmodule Mitm.Proto do
2+
use GenServer
3+
4+
def init(_) do
5+
{:ok, %{}}
6+
end
7+
8+
def connect_addr(address, port) do
9+
IO.inspect({:connect, address, port})
10+
{address, port}
11+
end
12+
13+
def on_connect(flow = %{dest: socket}) do
14+
:inet.setopts(socket, [{:active, true}, :binary])
15+
Map.merge(flow, %{start_time: :os.system_time(1), buf_s: <<>>, buf_c: <<>>})
16+
end
17+
18+
def on_close(socket, state) do
19+
state
20+
end
21+
22+
# server conn
23+
def proc_packet(:server, bin, s) do
24+
IO.puts("<- #{s.dest_addr} #{s.dest_port}")
25+
buf = s.buf_s <> bin
26+
{packets, buf} = unpad(buf)
27+
s = Map.put(s, :buf_s, buf)
28+
IO.inspect(packets)
29+
{:send, bin, s}
30+
end
31+
32+
# client conn
33+
def proc_packet(:client, bin, s) do
34+
IO.puts("-> #{s.dest_addr} #{s.dest_port}")
35+
buf = s.buf_c <> bin
36+
{packets, buf} = unpad(buf)
37+
s = Map.put(s, :buf_c, buf)
38+
IO.inspect(packets)
39+
{:send, bin, s}
40+
end
41+
42+
def unpad(data) do
43+
unpad(data, [])
44+
end
45+
46+
def unpad(<<len::32-little, data::binary>> = all, acc) do
47+
l = len - 16
48+
49+
case all do
50+
<<_::32-little, op::32-little, count::32-little, crc::32-little, data::binary-size(l),
51+
rest::binary>> ->
52+
pop = Bitwise.band(0xFFFF, op)
53+
top = Protocol.Opcode.from_num(pop) || pop
54+
unpad(rest, [{top, count, crc, data} || acc])
55+
56+
_ ->
57+
{:lists.reverse(acc), all}
58+
end
59+
end
60+
61+
def unpad(rest, acc) do
62+
{:lists.reverse(acc), rest}
63+
end
64+
end

ex/lib/packet_ids.ex

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
defmodule Protocol.Opcode do
2+
ids =
3+
File.read!("opcodes.cs")
4+
|> String.split(";")
5+
|> Enum.map(&String.trim/1)
6+
|> Enum.filter(&(&1 != ""))
7+
|> Enum.map(&String.replace(&1, "public const ePacketId ", ""))
8+
|> Enum.map(&String.split(&1, " = "))
9+
|> Enum.map(fn [a, b] -> {a, String.to_integer(b)} end)
10+
11+
as_map =
12+
Enum.map(ids, fn {a, b} -> {b, :erlang.binary_to_atom(a)} end)
13+
|> Map.new()
14+
15+
as_map_reverse =
16+
Enum.map(ids, fn {a, b} -> {:erlang.binary_to_atom(a), b} end)
17+
|> Map.new()
18+
19+
def from_num(x) do
20+
unquote(Macro.escape(as_map)) |> Map.get(x)
21+
end
22+
23+
def to_num(x) do
24+
unquote(Macro.escape(as_map_reverse)) |> Map.get(x)
25+
end
26+
end

ex/lib/proto.ex

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
defmodule CsProtoParser do
2+
@doc """
3+
Parses a C# file content and extracts BasePacket/EncryptPacket descendants and their ProtoMember fields.
4+
Returns a map with class information including encryption status and proto members.
5+
"""
6+
def parse(content) do
7+
# Match both BasePacket and EncryptPacket classes
8+
class_patterns = [
9+
{~r/\[ProtoContract\]\s*public class (\w+)\s*:\s*BasePacket[^{]*{([^}]+)}/, false},
10+
{~r/\[ProtoContract\]\s*public class (\w+)\s*:\s*EncryptPacket[^{]*{([^}]+)}/, true},
11+
# Simpler pattern for classes without body
12+
{~r/public class (\w+)\s*:\s*BasePacket[^{]*$/, false},
13+
{~r/public class (\w+)\s*:\s*EncryptPacket[^{]*$/, true}
14+
]
15+
16+
class_patterns
17+
|> Enum.flat_map(fn {pattern, is_encrypted} ->
18+
Regex.scan(pattern, content)
19+
|> Enum.map(fn
20+
# For matches with class body
21+
[_, class_name, class_body] ->
22+
proto_members = extract_proto_members(class_body)
23+
{class_name, %{
24+
encrypted: is_encrypted,
25+
proto_members: proto_members
26+
}}
27+
# For matches without class body
28+
[_, class_name] ->
29+
{class_name, %{
30+
encrypted: is_encrypted,
31+
proto_members: []
32+
}}
33+
end)
34+
end)
35+
|> Enum.into(%{})
36+
end
37+
38+
@doc """
39+
Extracts ProtoMember fields from a class body.
40+
Returns a list of tuples containing {field_name, proto_member_number, field_type}.
41+
"""
42+
def extract_proto_members(class_body) do
43+
proto_member_regex = ~r/\[ProtoMember\((\d+)\)\]\s*public\s+([^\s]+)\s+(\w+)\s*;/
44+
45+
Regex.scan(proto_member_regex, class_body || "")
46+
|> Enum.map(fn [_, number, type, field_name] ->
47+
{field_name, String.to_integer(number), type}
48+
end)
49+
end
50+
51+
def test() do
52+
# Example usage:
53+
content = """
54+
[ProtoContract]
55+
public class SC_PingToGateWay : BasePacket // TypeDefIndex: 1094
56+
{
57+
// Fields
58+
[ProtoMember(1)]
59+
public DateTime sendTime; // 0x18
60+
public DateTime recvTime; // 0x20
61+
[ProtoMember(2)]
62+
public DateTime serverUtcNow; // 0x28
63+
64+
// Properties
65+
public override ePacketId packetType { get; }
66+
67+
// Methods
68+
public override ePacketId get_packetType() { }
69+
public void .ctor() { }
70+
}
71+
"""
72+
73+
# Parse and print results
74+
result = CsProtoParser.parse(content)
75+
IO.inspect(result, label: "Parsed Proto Classes")
76+
end
77+
end

ex/mix.exs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ defmodule Ex.MixProject do
2121
# Run "mix help deps" to learn about dependencies.
2222
defp deps do
2323
[
24+
{:mitm, git: "https://github.com/xenomorphtech/mitm_ex.git"},
25+
{:protobuf_lite, "~> 0.1.0"}
2426
# {:dep_from_hexpm, "~> 0.3.0"},
2527
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
2628
]

ex/mix.lock

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
%{
2+
"dns": {:git, "https://github.com/xenomorphtech/elixir-dns-server.git", "bb319a0738fa92d7637c1d69d0c9e7197924cfc1", []},
3+
"mitm": {:git, "https://github.com/xenomorphtech/mitm_ex.git", "d18d6b1f6dbd7870b87af31864ae3c91621753a8", []},
4+
"protobuf_lite": {:hex, :protobuf_lite, "0.1.0", "7f1ad66fe3b74b7d0f2da276d8f263999ee55bc5119aaae8fcc430d7073d97c8", [:mix], [], "hexpm", "c588832eb24fc88575ecd60a7340aa83dc19f7e76d1a2c027e8e9b008a3cccb0"},
5+
"socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm", "f82ea9833ef49dde272e6568ab8aac657a636acb4cf44a7de8a935acb8957c2e"},
6+
}

0 commit comments

Comments
 (0)