commit 023cb3f8f45859d66208a7d834eaa93522701e50 Author: i2p Date: Thu Aug 27 11:22:11 2026 -0600 initial commit diff --git a/KeyGen.exe b/KeyGen.exe new file mode 100644 index 0000000..9edbb33 Binary files /dev/null and b/KeyGen.exe differ diff --git a/KeyGen.exe.i64 b/KeyGen.exe.i64 new file mode 100644 index 0000000..0555624 Binary files /dev/null and b/KeyGen.exe.i64 differ diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..c8ca0f4 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,75 @@ + ______ +(_____ \ + _____) )_____ ____ ____ ___ ___ +| __ /| ___ | \ / ___) _ \ /___) +| | \ \| ____| | | ( (__| |_| |___ | +|_| |_|_____)_|_|_|\____)___/(___/ + +© BreakingSecurity.net + + +************************ +* Zip Password * +************************ + +Zip Password is: BreakingSecurity.net + +************************ +* License Activation * +************************ + +To activate your Remcos Professional Edition license +(not needed for Remcos Free Edition): + +1) Open KeyGen.exe +2) Insert your BreakingSecurity.net registration email and password +3) Click "Generate Key" +4) Click "Activate Key" +5) License is activated automatically and immediately. + You should receive a confirmation email within a minute. + +************************ +* Quick Setup * +************************ + +This brief guide will help you out in establishing a successful connection using Remcos. + +For more in-depth instructions, consult: + +Instruction Manual: +https://BreakingSecurity.net/remcos/manual + +VideoTutorials: +https://BreakingSecurity.net/tutorials + +Support: +https://BreakingSecurity.net/support + + +1) INSTALL REMCOS + Remcos is portable and does not require an installation. + Just extract Remcos.exe file in any folder and execute it. + Zip Password is: BreakingSecurity.net + If later on you download a new Remcos update and want to keep all your settings, + just place the new Remcos.exe in the same folder. + +2) OPEN LISTENING PORT + The first step to do is open a TCP port for Remcos Controller. + This port will be used to listen for incoming connections. + Go to Local Settings -> Connection + to add a listening port. + Make sure your firewall allows Remcos connection. + +3) SETUP AGENT CONNECTION + Go to Agent Builder -> Connection + to specify where your Remcos Agent should connect. + You should enter the IP or DNS address and listening port of your Remcos Controller here. + +4) BUILD AGENT + Go to Agent Builder -> Build + to build a Remcos Agent. + Deploy the agent to the remote system and execute it. + +5) ESTABLISH CONNECTION + If the above steps were correctly done, + your new Remcos connection will popup in the Connections tab. \ No newline at end of file diff --git a/Remcos v7.2.2 Pro.exe b/Remcos v7.2.2 Pro.exe new file mode 100644 index 0000000..eaa0100 Binary files /dev/null and b/Remcos v7.2.2 Pro.exe differ diff --git a/how to run.txt b/how to run.txt new file mode 100644 index 0000000..2183f51 --- /dev/null +++ b/how to run.txt @@ -0,0 +1,6 @@ +Run server_only.py as admin first +when thats running then run launch_remcos.py as admin +aswell then bara bing bara boom it's cracked + +when launching launch_remcos.py it will give you a bunch +of errors just hit on ok until you see the main gui ok. diff --git a/launch_remcos.py b/launch_remcos.py new file mode 100644 index 0000000..3a6ec4c --- /dev/null +++ b/launch_remcos.py @@ -0,0 +1,95 @@ +""" +Launch Remcos with SSL_CERT_FILE + apply IAT patches. +Run WHILE server_only.py is running in another terminal. +""" +import ctypes, ctypes.wintypes as wt, struct, subprocess, os, sys, time + +PROCESS_ALL_ACCESS = 0x1F0FFF +PAGE_EXECUTE_READWRITE = 0x40 +MEM_COMMIT, MEM_RESERVE = 0x1000, 0x2000 +UNPACK_ADDR, UNPACK_SIG = 0x8EEED8, b'\x55\x8b\xec\x6a' + +kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) +OpenProcess = kernel32.OpenProcess; OpenProcess.restype = wt.HANDLE +ReadProcessMemory = kernel32.ReadProcessMemory; ReadProcessMemory.restype = wt.BOOL +WriteProcessMemory = kernel32.WriteProcessMemory; WriteProcessMemory.restype = wt.BOOL +VirtualAllocEx = kernel32.VirtualAllocEx; VirtualAllocEx.restype = wt.LPVOID +VirtualProtectEx = kernel32.VirtualProtectEx; VirtualProtectEx.restype = wt.BOOL +CloseHandle = kernel32.CloseHandle + +def read_mem(h, addr, sz): + buf = ctypes.create_string_buffer(sz); n = ctypes.c_size_t(0) + return buf.raw[:n.value] if ReadProcessMemory(h, addr, buf, sz, ctypes.byref(n)) else None + +def write_mem(h, addr, data): + old = wt.DWORD(0) + VirtualProtectEx(h, addr, len(data), PAGE_EXECUTE_READWRITE, ctypes.byref(old)) + n = ctypes.c_size_t(0); buf = ctypes.create_string_buffer(data) + ok = WriteProcessMemory(h, addr, buf, len(data), ctypes.byref(n)) + VirtualProtectEx(h, addr, len(data), old.value, ctypes.byref(old)) + return ok and n.value == len(data) + +def main(): + d = os.path.dirname(os.path.abspath(__file__)) + exe = os.path.join(d, "Remcos v7.2.2 Pro.exe") + + # Set SSL env + ca = os.path.join(d, "certs", "ca_bundle.pem") + if os.path.exists(ca): + os.environ["SSL_CERT_FILE"] = ca + os.environ["SSL_CERT_DIR"] = os.path.join(d, "certs") + print(f"[+] SSL_CERT_FILE={ca}") + + # Kill old + subprocess.run(['taskkill', '/F', '/IM', 'Remcos v7.2.2 Pro.exe'], capture_output=True) + time.sleep(1) + + # Launch + proc = subprocess.Popen([exe], cwd=d) + pid = proc.pid; print(f"[+] PID {pid}") + + h = None + for _ in range(30): + h = OpenProcess(PROCESS_ALL_ACCESS, False, pid) + if h: break + time.sleep(0.1) + if not h: print("[-] Can't open"); return + + # Wait unpack + print("[*] Waiting for unpack...") + t0 = time.time() + while time.time() - t0 < 45: + if proc.poll() is not None: print("[-] Exited early"); CloseHandle(h); return + if read_mem(h, UNPACK_ADDR, 4) == UNPACK_SIG: break + time.sleep(0.05) + else: print("[-] Timeout"); CloseHandle(h); return + print(f"[+] Unpacked {time.time()-t0:.1f}s"); time.sleep(0.2) + + # Stubs + page = VirtualAllocEx(h, None, 4096, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) + stub = bytearray(32) + stub[0x00] = 0xC3 # ret + stub[0x04:0x07] = b'\xC2\x04\x00' # ret 4 + stub[0x08:0x10] = b'\xB8\x01\x00\x00\x00\xC2\x18\x00' # CryptVerify -> TRUE + write_mem(h, page, bytes(stub)) + + # Exit hooks + for addr, off, name in [(0x9DF18C,0,"Halt"),(0x4C36428,4,"PostQuitMessage"), + (0xA1007C,4,"ExitProcess1"),(0x4C36590,4,"ExitProcess2"),(0x4C36AE8,4,"ExitProcess3")]: + write_mem(h, addr, struct.pack(' 127.0.0.1") + else: + print(f" [-] {domains[0]}: {r.stderr.strip()[:80]}") + + subprocess.run(["ipconfig", "/flushdns"], capture_output=True, timeout=10) + subprocess.run(["powershell", "-Command", "Clear-DnsClientCache; Register-DnsClient"], + capture_output=True, timeout=10) + +def cleanup_nrpt(): + for guid, _ in NRPT_GUIDS: + ps = f"Remove-Item -Path '{NRPT_BASE}\\{guid}' -Recurse -Force -ErrorAction SilentlyContinue" + subprocess.run(["powershell", "-Command", ps], capture_output=True, timeout=10) + subprocess.run(["ipconfig", "/flushdns"], capture_output=True, timeout=10) + +# ============================================================ +# DNS Server +# ============================================================ +class DNSHandler(socketserver.BaseRequestHandler): + def handle(self): + data = self.request[0] + sock = self.request[1] + try: + domain = self._parse_domain(data).lower().rstrip(".") + redirect = any(domain == d or domain.endswith("." + d) + for d in REDIRECT_DOMAINS) + if redirect: + resp = self._build_response(data, "127.0.0.1") + sock.sendto(resp, self.client_address) + else: + fwd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + fwd.settimeout(3) + fwd.sendto(data, (REAL_DNS, 53)) + try: + r, _ = fwd.recvfrom(4096) + sock.sendto(r, self.client_address) + except socket.timeout: + pass + fwd.close() + except: + pass + + def _parse_domain(self, data): + parts, idx = [], 12 + while idx < len(data): + l = data[idx] + if l == 0: break + idx += 1 + parts.append(data[idx:idx+l].decode("ascii", errors="replace")) + idx += l + return ".".join(parts) + + def _build_response(self, query, ip): + resp = bytearray(query[:2]) + b'\x81\x80' + query[4:6] + b'\x00\x01\x00\x00\x00\x00' + idx = 12 + while idx < len(query): + if query[idx] == 0: + idx += 5 + break + idx += 1 + query[idx] + resp += query[12:idx] + resp += b'\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04' + resp += socket.inet_aton(ip) + return bytes(resp) + +# ============================================================ +# HTTP/HTTPS Server +# ============================================================ +class FakeHandler(http.server.BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + ts = datetime.now().strftime("%H:%M:%S") + print(f" [{ts}] {fmt % args}") + + def send_text(self, text, code=200): + data = text.encode("utf-8") + self.send_response(code) + self.send_header("Content-Type", "text/plain") + self.send_header("Content-Length", str(len(data))) + self.send_header("Connection", "close") + self.end_headers() + self.wfile.write(data) + + def route(self): + path = urlparse(self.path).path.lower() + host = self.headers.get("Host", "") + qs = parse_qs(urlparse(self.path).query) + print(f" -> {self.command} {self.path} (Host: {host})") + # Dump ALL headers for debugging + for h_name, h_val in self.headers.items(): + print(f" {h_name}: {h_val}") + + if "whitelist" in path: + print(f" <- Whitelist: EMPTY") + self.send_text("") + return + if "signalabuse" in path: + print(f" <- Abuse absorbed") + self.send_text("") + return + if "licpost" in path or ("keygen" in path and "lic" in path.lower()): + lic_raw = qs.get("LIC", [""])[0] + parts = lic_raw.split("|") + print(f" ***** KeyGen LicPost! *****") + print(f" Parts: {parts}") + # Try response matching request format: pipe-delimited after "0\n" + key = parts[0] if len(parts) > 0 else "" + email = parts[1] if len(parts) > 1 else "" + # Format: 0\nkey|email|product|expiry|type|version + resp = f"0\n{key}|{email}|Remcos|20301231|Pro|7.2.2" + print(f" <- Responding: '{resp}'") + self.send_text(resp) + return + if "upd_pro" in path: + print(f" <- Version: {VERSION}") + self.send_text(VERSION + "\n") + return + # PeriodicCheck - license validation with hash + expiry + if "periodiccheck" in path: + lic = qs.get("LIC", ["?"])[0] + resp = "49ef9592748fac8986f0d360454dbab0\n20301231\nRemcos" + print(f" ***** PeriodicCheck (LIC={lic[:24]}) -> {repr(resp)} *****") + self.send_text(resp) + return + # Auth/license check - sign with our private key + if "auth" in path or "check" in path or "verify" in path or "validate" in path: + print(f" ***** Auth endpoint: {self.path} *****") + self.send_text("0\n20301231\nPro\n7.2.2") + return + if "onlinecheck" in path: + print(f" <- OnlineCheck: {VERSION}") + self.send_text(VERSION + "\n") + return + if "/line" in path or "ip-api" in host: + print(f" <- GeoIP") + self.send_text(GEO_RESPONSE + "\n") + return + print(f" *** UNKNOWN ENDPOINT: {self.path} ***") + print(f" *** Host: {host} ***") + # Return "0" instead of empty - empty might cause range check errors + self.send_text("0") + + def do_GET(self): self.route() + def do_POST(self): + cl = int(self.headers.get("Content-Length", 0)) + body = self.rfile.read(cl) if cl > 0 else b"" + if body: + try: print(f" POST body: {body[:300].decode('utf-8', errors='replace')}") + except: print(f" POST body: {body[:100].hex()}") + self.route() + +# ============================================================ +# Main +# ============================================================ +def main(): + print("=" * 60) + print(" Fake Server (standalone) - stays running") + print(" Launch Remcos/KeyGen yourself while this runs") + print("=" * 60) + + if not ctypes.windll.shell32.IsUserAnAdmin(): + print("[-] Need Administrator! Right-click -> Run as admin") + return 1 + + # Setup + generate_certs() + install_ca() + + # CA bundle for OpenSSL apps + ca_bundle = os.path.join(CERT_DIR, "ca_bundle.pem") + try: + import certifi + system_ca = certifi.where() + except ImportError: + system_ca = None + with open(ca_bundle, "w") as out: + with open(CA_CERT) as f: out.write(f.read() + "\n") + if system_ca and os.path.exists(system_ca): + with open(system_ca) as f: out.write(f.read()) + os.environ["SSL_CERT_FILE"] = ca_bundle + os.environ["SSL_CERT_DIR"] = CERT_DIR + + # Start servers + dns = socketserver.UDPServer(("127.0.0.1", 53), DNSHandler) + threading.Thread(target=dns.serve_forever, daemon=True).start() + print("[+] DNS on 127.0.0.1:53") + + http_srv = http.server.HTTPServer(("0.0.0.0", 80), FakeHandler) + threading.Thread(target=http_srv.serve_forever, daemon=True).start() + print("[+] HTTP on 0.0.0.0:80") + + try: + class LoggingHTTPS(http.server.HTTPServer): + def handle_error(self, request, client_address): + print(f" [SSL ERROR] from {client_address}: {sys.exc_info()[1]}") + https_srv = LoggingHTTPS(("0.0.0.0", 443), FakeHandler) + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ctx.load_cert_chain(SRV_CERT, SRV_KEY) + https_srv.socket = ctx.wrap_socket(https_srv.socket, server_side=True) + threading.Thread(target=https_srv.serve_forever, daemon=True).start() + print("[+] HTTPS on 0.0.0.0:443") + except Exception as e: + print(f"[-] HTTPS failed: {e}") + + # Port 45000 - Viotto packer license validation (raw TCP protocol!) + def handle_viotto_client(conn, addr): + print(f"\n *** PORT 45000 CONNECTION from {addr} ***") + conn.settimeout(5) + try: + # Read whatever the client sends + data = conn.recv(4096) + print(f" *** RECEIVED ({len(data)} bytes): {data[:200].hex()}") + try: + print(f" *** AS TEXT: {data[:200].decode('ascii', errors='replace')}") + except: + pass + # Echo back for now - we need to see the protocol first + conn.sendall(data) + print(f" *** Echoed {len(data)} bytes back") + except socket.timeout: + print(f" *** PORT 45000: recv timeout (client didn't send data)") + except Exception as e: + print(f" *** PORT 45000 error: {e}") + finally: + conn.close() + + def viotto_server(): + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + srv.bind(("0.0.0.0", 45000)) + srv.listen(5) + print("[+] Raw TCP on 0.0.0.0:45000 (Viotto license port!)") + while True: + conn, addr = srv.accept() + threading.Thread(target=handle_viotto_client, args=(conn, addr), daemon=True).start() + + threading.Thread(target=viotto_server, daemon=True).start() + + # NRPT + setup_nrpt() + + # Verify + time.sleep(1) + for domain in ["breakingsec.io", "breakingsecurity.net"]: + try: + result = socket.getaddrinfo(domain, 443) + ip = result[0][4][0] + status = "OK" if ip == "127.0.0.1" else f"WRONG ({ip})" + print(f" {domain} -> {ip} [{status}]") + except Exception as e: + print(f" {domain} -> ERROR: {e}") + + print() + print("=" * 60) + print(" RUNNING. Now launch KeyGen.exe or Remcos manually.") + print(" Press Ctrl+C to stop and clean up.") + print("=" * 60) + print() + + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + pass + finally: + print("\n[*] Cleaning up...") + cleanup_nrpt() + print("[+] NRPT removed") + remove_ca() + print("[+] CA removed") + +import ctypes +if __name__ == "__main__": + sys.exit(main()) diff --git a/zip_password.txt b/zip_password.txt new file mode 100644 index 0000000..19f86f8 --- /dev/null +++ b/zip_password.txt @@ -0,0 +1,2 @@ +Zip password is: +BreakingSecurity.net \ No newline at end of file