Android Question Python to B4A convert project PROXY - PAYLOAD

davidcr85

Member
I have a python project working fine, which I would like to run in B4X. In general the code creates a local proxy server running on port 8888 which connects to a remote host by sending a payload. I'm not sure how to start converting which libraries do you recommend? I leave the main code here for analysis.

Main.py:
import configparser
import subprocess
import multiprocessing
import time
import os
import json

bg=''
G = bg+'\033[32m'
O = bg+'\033[33m'
GR = bg+'\033[37m'
R = bg+'\033[31m'


def main():
    
    os.system("echo -----------------logs--------------------------------- > logs.txt")
    jsondata = {
        "mode" : '',
            "payload" : '',
                "proxy" : '',
                    "sni" : "",
      }

    os.system('cls')
    print('---------------------------------------------------------------')
    jsondata["mode"] = confParse()['mode']['connection_mode']   
    jsondata["payload"] = confParse()['config']['payload']
    jsondata["proxy"] = confParse()['config']['proxyip'] +':' +confParse()['config']['proxyport']
    jsondata["sni"] = confParse()['sni']['server_name']

    if jsondata["mode"] == '0':
        print( f'{O}Direct SSH{GR}')

    if jsondata["mode"] == '2':
        print(f'{O}SNI : {GR} {jsondata["sni"]}')

    if jsondata["mode"] in ['1','3']:
        print(f'{O}payload :\n{GR} {jsondata["payload"]}\n')
        #if len(jsondata["proxy"].split(':')[1]) > 1:
        print(f'{O}proxy :{GR} ', jsondata["proxy"] if len(jsondata["proxy"].split(':')[1]) > 1 else None,end='\n\n')

        print(f'{O}SSL/TLS :{GR}', jsondata["sni"] if jsondata["mode"] =='3' else None)
    
    threadServ = multiprocessing.Process(target=ServRun)
    threadServ.start()

    sshStart = multiprocessing.Process(target=sshrun).start()
    
    return readlogs()
    
def readlogs():
    OneTimeOutput = []
    while True:
        try:
            with open('logs.txt','r') as file:
                time.sleep(1)
                end = 0
                logs = file.readlines()
                for line in logs:
                    if line not in OneTimeOutput:
                        OneTimeOutput.append(line)
                        print(line)
                        if line.split(":")[-1].split("-")[0].strip()=='SSH':
                            os.system("echo -----------------logs--------------------------------- > logs.txt")
                            runProxifier()
                            end +=1
                            break
                if end:break
        except KeyboardInterrupt:
            return serviceManage()
    return serviceManage()

def killProcessid(target):
    
    findProcess = subprocess.Popen(['tasklist','|','findstr', target],shell=True,stdout= subprocess.PIPE,stderr=subprocess.STDOUT)
    for line in findProcess.stdout:
        pid = line.decode('utf-8','ignore').split()[1]
        killprocess = subprocess.Popen(['taskkill','/f','/pid',pid],shell=True,stdout= subprocess.PIPE,stderr=subprocess.STDOUT)
    return "Done"

def ServRun():
    #path = os.path.abspath(os.path.curdir)+'/lib'
    Serv_Cmd = subprocess.Popen(['python','tunnel.py','8888'] , shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
                
def confParse():
    config = configparser.ConfigParser()
    try:
        config.read_file(open('settings.ini'))
    except Exception as e:
        pass
    return config

def sshrun():
    #ssh load settings
    ssh_server = confParse()['ssh']['host'] 
    ssh_port = confParse()['ssh']['port']
    username = confParse()['ssh']['username']
    password = confParse()['ssh']['password']

    #local proxy
    proxy_ip = '127.0.0.1'
    proxy_port = '8888'

    #run ssh command
    ssh_cmd = subprocess.Popen(( f'BvSsh.exe -host={ssh_server} -user={username} -pw={password} -port={ssh_port} -proxy=y -proxyType=HTTP -proxyServer=127.0.0.1 -proxyPort={proxy_port} -proxyFwding=y -proxyListIntf=127.0.0.1 -proxyListPort=1080 -loginOnStartup -reconnect=Always -reconnTimeout=2'),stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
    
def runProxifier():
    proxify = subprocess.Popen(('"C:\\Program Files (x86)\\Proxifier\\Proxifier.exe" socks5profile.ppx '))

def serviceManage():
    try:
        index_input = int(input('1 - To Disconnect \n2 - To Reconnect \n3 - show logs\n choose op num: '))
        services = ["Proxifier","BvSsh.exe",'python']
        if index_input in [1,2] :
            services = [services[0:2] if index_input == 2 else services[:]][0]
            for ev in services:
                killProcessid(ev)
        if index_input == 2 :   
            return main()
        if index_input == 3:
            readlogs()
        if index_input not in [1,2,3]:
            print('Operation number not listed')
            return serviceManage()
        
    except Exception as e:
        print(e)
        print('A number required ')
        return serviceManage()

        
if __name__=='__main__':
    main()

tunnel.py:
import ssl,os,certifi,sys
import socket
import time
import select
import threading
from inject import injector
import configparser

bg=''
G = bg+'\033[32m'
O = bg+'\033[33m'
GR = bg+'\033[37m'
R = bg+'\033[31m'

Buffer_lenght = 4096 * 4

class Tun(injector):
    def __init__(self):
        self.localip = '127.0.0.1'
        self.LISTEN_PORT = int(sys.argv[1])

    def conf(self):
        config = configparser.ConfigParser()
        try:
            config.read_file(open('settings.ini'))
        except Exception as e:
            self.logs(e)
        return config

    def extraxt_sni(self,config):
        sni = config['sni']['server_name']
        return sni

    def gethost(self,config):
        host=config['ssh']['host']
        return host

    def proxy(self,config):
        proxyhost = config['config']['proxyip']
        proxyport = int(config['config']['proxyport'])
        return [proxyhost,proxyport]

    def conn_mode(self,config):
        mode = config['mode']['connection_mode']
        return mode

    def tunneling(self,client,sockt):
        connected = True
        while connected == True:
            r, w, x = select.select([client,sockt], [], [client,sockt],3)
            if x: connected = False; break
            for i in r:
                try:
                    data = i.recv(Buffer_lenght)
                    if not data: connected = False; break
                    if i is sockt:
                        client.send(data)
                    else:
                        sockt.send(data)
                except Exception as e:
                    self.logs(f'{R} {e}{GR}')
                    connected = False;break
        client.close()
        sockt.close()
        
    def destination(self,sock_server, address):
        try:
            request = sock_server.recv(9124).decode()
            host = self.gethost(self.conf())
            port = request.split(':')[-1].split()[0]
            try:
                proxy_ip=self.proxy(self.conf())[0]
                proxy_port=self.proxy(self.conf())[1]
            except ValueError:
                proxy_ip = host
                proxy_port = port
            sock_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            sock_client.connect((proxy_ip,int(proxy_port)))
            self.logs(f'{O}[TCP] {G}connected to {proxy_ip}:{proxy_port}{GR}')

            if int(self.conn_mode(self.conf())) == 2:
                SNI_HOST = self.extraxt_sni(self.conf())
                context = ssl.SSLContext(ssl.PROTOCOL_TLS)
                sock_client = context.wrap_socket(sock_client,server_hostname=str(SNI_HOST))
                context.verify_mode  = ssl.CERT_REQUIRED
                context.load_verify_locations(
                cafile=os.path.relpath(certifi.where()),
                capath=None,cadata=None)
                self.logs(f'{O}[TCP] Handshaked successfully to {SNI_HOST}{GR}')
                try:
                    self.logs(f'''{O}[TCP] Protocol :{G}{sock_client.version()}\n{O}Ciphersuite :{G} {sock_client.cipher()[0]}\n{O}Peerprincipal:{G} C={sock_client.getpeercert()["subject"][1][0][1]}, ST={sock_client.getpeercert()["subject"][1][0][1]} , L={sock_client.getpeercert()["subject"][2][0][1]} , O={sock_client.getpeercert()["subject"][3][0][1]} , CN={sock_client.getpeercert()["subject"][4][0][1]}  {GR}''')
                except:
                    self.logs(f'''{O}[TCP] Protocol :{G}{sock_client.version()}\n{O}Ciphersuite :{G} {sock_client.cipher()[0]}\n{O}Peerprincipal:{G} {sock_client.getpeercert()["subject"]}''')
                sock_server.send(b"HTTP/1.1 200 Connection Established\r\n\r\n")

            elif int(self.conn_mode(self.conf())) == 3:
                SNI_HOST = self.extraxt_sni(self.conf())
                context = ssl.SSLContext(ssl.PROTOCOL_TLS)
                sock_client = context.wrap_socket(sock_client,server_hostname=str(SNI_HOST))
                context.verify_mode  = ssl.CERT_REQUIRED
                context.load_verify_locations(
                cafile=os.path.relpath(certifi.where()),
                capath=None,cadata=None)
                self.logs(f'Handshaked successfully to {SNI_HOST}')
                try:
                    self.logs(f'''{O}[TCP] Protocol :{G}{sock_client.version()}\n{O}Ciphersuite :{G} {sock_client.cipher()[0]}\n{O}Peerprincipal:{G} C={sock_client.getpeercert()["subject"][1][0][1]}, ST={sock_client.getpeercert()["subject"][1][0][1]} , L={sock_client.getpeercert()["subject"][2][0][1]} , O={sock_client.getpeercert()["subject"][3][0][1]} , CN={sock_client.getpeercert()["subject"][4][0][1]}  {GR}''')
                except:
                    self.logs(f'''{O}[TCP] Protocol :{G}{sock_client.version()}\n{O}Ciphersuite :{G} {sock_client.cipher()[0]}\n{O}Peerprincipal:{G} {sock_client.getpeercert()["subject"]}''')
                injector.connection(self,sock_server,sock_client,kwargs={'SSH':f'{host}:{port}','PROXY':f'{proxy_ip}:{proxy_port}'})

            else:
                injector.connection(self,sock_server,sock_client,kwargs={'SSH':f'{host}:{port}','PROXY':f'{proxy_ip}:{proxy_port}'})
            self.tunneling(sock_server,sock_client)
        except Exception as e:
            self.logs(f'{e}')
    def create_connection(self):
        
        for res in socket.getaddrinfo(self.localip, self.LISTEN_PORT, socket.AF_UNSPEC,socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
            af, socktype, proto, canonname, sa = res
            try:
                sockt = socket.socket(af, socktype, proto)
            except OSError as msg:
                self.logs(str(msg))
                continue
            try:
               localAddress = socket.gethostbyname("localhost")
               sockt.bind((localAddress,self.LISTEN_PORT))
               sockt.listen(1)
            except OSError as msg:
                self.logs(str(msg))
                sockt.close()
                    
            if sockt:
              pass
            self.logs('Waiting for incoming connection to : {}:{}\n'.format(self.localip,self.LISTEN_PORT))
            while True:
                try:
                  client, address = sockt.accept()
                  thr = threading.Thread(target=self.destination, args=(client, address))
                  thr.start()
                except :
                   sockt.close()
                   break
              
    def logs(self,log):
        logtime = str(time.ctime()).split()[3]
        logfile = open('logs.txt','a')
        logfile.write(f'[{logtime}] : {str(log)}\n')
if __name__=='__main__':
    start = Tun()
    start.create_connection()

inject.py:
import time
import socket
import configparser
import re
import sys
import user_agent

bg=''
G = bg+'\033[32m'
O = bg+'\033[33m'
GR = bg+'\033[37m'
R = bg+'\033[31m'



class injector():
    def __init__(self):
        pass

    def conf(self):
        config = configparser.ConfigParser()
        try:
            config.read_file(open('settings.ini'))
        except Exception as e:
            self.logs(e)
        return config

    def getpayload(self,config):
        payload = config['config']['payload']
        return payload

    def proxy(self,config):
        proxyhost = config['config']['proxyip']
        proxyport = int(config['config']['proxyport'])
        return [proxyhost,proxyport]
    def conn_mode(self,config):
        mode = config['mode']['connection_mode']
        return mode

    def auto_rep(self,config):
        result = config['config']['auto_replace']
        return result
    


    def payloadformating(self,payload,**kwargs):

        host, port = kwargs["kwargs"]["SSH"].split(':')[0],kwargs["kwargs"]["SSH"].split(':')[1]
        proxy_ip,proxy_port = kwargs["kwargs"]["PROXY"].split(':')[0],kwargs["kwargs"]["PROXY"].split(':')[1]
        User_Agent = user_agent.generate_user_agent()
        
        payload = payload.replace('[crlf]','\r\n')
        payload = payload.replace('[crlf*2]','\r\n\r\n')
        payload = payload.replace('[cr]','\r')
        payload = payload.replace('[lf]','\n')
        payload = payload.replace('[protocol]','HTTP/1.0')
        payload = payload.replace('[ua]',User_Agent) 
        payload = payload.replace('[raw]',f'CONNECT {kwargs["kwargs"]["SSH"]}  HTTP/1.0\r\n\r\n')
        payload = payload.replace('[real_raw]',f'CONNECT {kwargs["kwargs"]["SSH"]} HTTP/1.0\r\n\r\n')
        payload = payload.replace('[netData]',f'CONNECT {kwargs["kwargs"]["SSH"]} HTTP/1.0')
        payload = payload.replace('[realData]',f'CONNECT {kwargs["kwargs"]["SSH"]} HTTP/1.0')                   
        payload = payload.replace('[split_delay]','[delay_split]')
        payload = payload.replace('[split_instant]','[instant_split]')
        payload = payload.replace('[method]','CONNECT')
        payload = payload.replace('[lfcr]','\n\r')
        payload = payload.replace('[host_port]',host+':'+port)
        payload = payload.replace('[host]',host)
        payload = payload.replace('[port]',port)
        payload = payload.replace('[IP]',host)
        payload = payload.replace('[PORT]',port)
        payload = payload.replace('[proxy]',kwargs["kwargs"]["PROXY"])
        payload = payload.replace('[ssh]',kwargs["kwargs"]["PROXY"])
        payload = payload.replace('[auth]','')
        payload = payload.replace('[split]' ,'=1.0=')
        payload = payload.replace('[delay_split]'  ,'=1.5=')
        payload = payload.replace('[instant_split]','=0.0=')
        return payload

    def connection(self,client, server,**kwargs):
            if int(self.conn_mode(self.conf())) == 0:
                return self.get_resp(server=server,client=client)
                              
            else:
                payloads = self.payloadformating(self.getpayload(self.conf()),**kwargs).split('=')
                
            for payload in payloads:
                  if payload in ['1.0','1.5','0.0'] :
                    time.sleep(float(payload))
                  else:
                    self.logs(f'{O} sending payload : {payload.encode()}{GR}')
                    server.send(payload.encode())
            return self.get_resp(server=server,client=client)

    def get_resp(self,server,client) :
        packet = server.recv(1024)
        status = packet.decode('utf-8','ignore').split('\r\n')[0]
        serverHandshakeResponse = status if status.split('-')[0]=='SSH' else False
        if serverHandshakeResponse:
            self.logs(f'response : {serverHandshakeResponse}')
            client.send(packet)
            return True
        else:
            if re.match(r'HTTP/\d(\.\d)? \d\d\d ',status):
                self.logs(f'response : {status}')
                client.send(b'HTTP/1.1 200 Connection established\r\n\r\n')
                return self.get_resp(server,client)

    def logs(self,log):
        logtime = str(time.ctime()).split()[3]
        logfile = open('logs.txt','a')
        logfile.write(f'[{logtime}] : {str(log)}\n')
 
Top