mirror of
https://github.com/xweiba/location-spoofer.git
synced 2026-09-24 15:41:56 +08:00
release: PaopaoLocationSpoofer v1.0.0
- iOS 虚拟定位工具,基于本地 HTTP 代理 MITM 方案 - MapKit 原生地图体验,支持搜索、收藏、实时定位 - 完整的设置引导流程(证书安装、WiFi 代理配置、环境验证) - 支持 iOS 15+,SwiftUI 构建
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// certificateServer exposes a device-specific CA download before the Packet
|
||||
// Tunnel starts and a TLS endpoint whose successful default validation proves
|
||||
// that iOS has installed and fully trusted that CA.
|
||||
type certificateServer struct {
|
||||
httpServer *http.Server
|
||||
httpsServer *http.Server
|
||||
httpLn net.Listener
|
||||
httpsLn net.Listener
|
||||
leafSHA256 string
|
||||
closeOnce sync.Once
|
||||
closeErr error
|
||||
}
|
||||
|
||||
func startCertificateServer(caCertPEM, caKeyPEM []byte) (*certificateServer, error) {
|
||||
ca, err := parseCA(caCertPEM, caKeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ca.Leaf.IsCA {
|
||||
return nil, errors.New("certificate server requires a CA certificate")
|
||||
}
|
||||
|
||||
leaf, leafDER, err := issueLoopbackLeaf(ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rootDER := ca.Leaf.Raw
|
||||
httpLn, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpsLn, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
_ = httpLn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
downloadMux := http.NewServeMux()
|
||||
downloadMux.HandleFunc("/ca.cer", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/x-x509-ca-cert")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="LocationSpoofer-CA.cer"`)
|
||||
_, _ = w.Write(rootDER)
|
||||
})
|
||||
|
||||
probeMux := http.NewServeMux()
|
||||
probeMux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte("ok\n"))
|
||||
})
|
||||
|
||||
server := &certificateServer{
|
||||
httpServer: &http.Server{Handler: downloadMux},
|
||||
httpsServer: &http.Server{Handler: probeMux},
|
||||
httpLn: httpLn,
|
||||
httpsLn: httpsLn,
|
||||
leafSHA256: sha256Base64(leafDER),
|
||||
}
|
||||
go func() {
|
||||
if err := server.httpServer.Serve(httpLn); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
logEvent("certificate download server error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
tlsListener := tls.NewListener(httpsLn, &tls.Config{Certificates: []tls.Certificate{leaf}, MinVersion: tls.VersionTLS12})
|
||||
if err := server.httpsServer.Serve(tlsListener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
logEvent("certificate probe server error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func issueLoopbackLeaf(ca *tls.Certificate) (tls.Certificate, []byte, error) {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
serialLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serial, err := rand.Int(rand.Reader, serialLimit)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: serial,
|
||||
Subject: pkix.Name{CommonName: "Location Spoofer Local Trust Probe"},
|
||||
NotBefore: now.Add(-time.Hour),
|
||||
NotAfter: now.Add(24 * time.Hour),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
},
|
||||
DNSNames: []string{"localhost"},
|
||||
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
}
|
||||
der, err := x509.CreateCertificate(rand.Reader, template, ca.Leaf, &privateKey.PublicKey, ca.PrivateKey)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
keyDER, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
|
||||
leaf, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
leaf.Leaf, err = x509.ParseCertificate(der)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
return leaf, der, nil
|
||||
}
|
||||
|
||||
func sha256Base64(data []byte) string {
|
||||
sum := sha256.Sum256(data)
|
||||
return base64.StdEncoding.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func (s *certificateServer) DownloadURL() string {
|
||||
return "http://" + s.httpLn.Addr().String() + "/ca.cer"
|
||||
}
|
||||
|
||||
func (s *certificateServer) ProbeURL() string {
|
||||
return "https://" + s.httpsLn.Addr().String() + "/health"
|
||||
}
|
||||
|
||||
func (s *certificateServer) LeafSHA256() string { return s.leafSHA256 }
|
||||
|
||||
func (s *certificateServer) Close() error {
|
||||
s.closeOnce.Do(func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
if err := s.httpServer.Shutdown(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
s.closeErr = err
|
||||
}
|
||||
if err := s.httpsServer.Shutdown(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) && s.closeErr == nil {
|
||||
s.closeErr = err
|
||||
}
|
||||
})
|
||||
return s.closeErr
|
||||
}
|
||||
Reference in New Issue
Block a user