Files

284 lines
9.5 KiB
Go

package main
import (
"os"
"os/exec"
"strings"
"strconv"
"math/rand"
"encoding/hex"
"time"
"net" /* for MAC address parsing */
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/dialog"
)
/* su-executor, returns standard output */
func suexec(cmdstr string) string {
out, err := exec.Command("su", "-c", cmdstr).Output()
if err != nil {
return err.Error()
}
return string(out)
}
/* calculate Luhn checksum over 14 IMEI digits */
func calcLuhn(num string) int {
sum := 0
dd := 0
for i, d := range num {
if d >= 48 && d < 58 {
dd = int(d) - 48
if i%2 == 1 {
dd += dd
if dd > 9 {
dd -= 9
}
}
sum += dd
}
}
sum %= 10
if sum != 0 {
sum = 10 - sum
}
return sum
}
/* generate an IMEI by TAC */
func genimei(tac string) string {
var imeisb strings.Builder
imeisb.WriteString(tac) /* start with the prefix */
for i:=0; i < 14; i++ {
imeisb.WriteString(strconv.Itoa(rand.Intn(10)))
}
imei := imeisb.String()[:14] /* only take the first 14 digits of the result */
return imei + strconv.Itoa(calcLuhn(imei))
}
/* generate a MAC address by TAC/prefix */
func genmac(pref string) string {
var macsb strings.Builder
bytes := make([]byte, 6)
rand.Read(bytes)
macsb.WriteString(strings.ReplaceAll(pref, ":", ""))
macsb.WriteString(hex.EncodeToString(bytes))
premac := macsb.String()[:12] /* only use the first 12 hex digits of the result */
macbytes, err := hex.DecodeString(premac)
if err == nil {
return strings.ToUpper(net.HardwareAddr(macbytes).String())
} else {
return "00:00:00:00:00:00"
}
}
/* GUI entry point */
func main() {
/* init the app */
rand.Seed(time.Now().UTC().UnixNano())
lexiapp := app.New()
mainwin := lexiapp.NewWindow("lexipwn")
/* check for root access/su availability */
_, err := exec.LookPath("su")
if err != nil {
dialog.ShowInformation("lexipwn", "Root access is required to run lexipwn!", mainwin)
return
}
/* extract lexipwn-cli to an accessible location */
clipath := lexiapp.Storage().RootURI().Path() + "/lexipwn"
os.WriteFile(clipath, resourceLexipwn.StaticContent, 0777)
/* input fields and their labels */
imei1field := widget.NewEntry()
imei1lbl := widget.NewLabel("IMEI 1")
imei2field := widget.NewEntry()
imei2lbl := widget.NewLabel("IMEI 2")
psnfield := widget.NewEntry()
psnlbl := widget.NewLabel("PSN")
dsnfield := widget.NewEntry()
dsnlbl := widget.NewLabel("DSN")
wlanmacfield := widget.NewEntry()
wlanmaclbl := widget.NewLabel("WLAN MAC address")
btmacfield := widget.NewEntry()
btmaclbl := widget.NewLabel("BT MAC address")
pcbcfgfield := widget.NewEntry()
pcbcfglbl := widget.NewLabel("PCB config")
devcfgfield := widget.NewEntry()
devcfglbl := widget.NewLabel("Dev config")
skufield := widget.NewEntry()
skulbl := widget.NewLabel("SKU")
coofield := widget.NewEntry()
coolbl := widget.NewLabel("COO")
dpcfield := widget.NewEntry()
dpclbl := widget.NewLabel("DPC")
wccfield := widget.NewEntry()
wcclbl := widget.NewLabel("WCC")
bootmodelbl := widget.NewLabel("Boot mode")
bootmodefield := widget.NewRadioGroup([]string{"normal", "factory"}, func(val string){})
tacprefixfield := widget.NewEntry()
tacprefixlbl := widget.NewLabel("IMEI prefix/TAC")
macprefixfield := widget.NewEntry()
macprefixlbl := widget.NewLabel("MAC prefix")
atcmdfield := widget.NewEntry()
atcmdres := widget.NewMultiLineEntry()
atcmdres.SetMinRowsVisible(7)
atcmdres.Wrapping = fyne.TextWrapWord
fieldgrid := container.New(layout.NewGridLayout(2), imei1lbl, imei1field,
imei2lbl, imei2field, psnlbl, psnfield, dsnlbl, dsnfield,
wlanmaclbl, wlanmacfield, btmaclbl, btmacfield, pcbcfglbl, pcbcfgfield,
devcfglbl, devcfgfield, skulbl, skufield, coolbl, coofield, dpclbl, dpcfield,
wcclbl, wccfield)
/* control buttons */
loadbtn := widget.NewButton("Load devinfo", func() {
rawlist := suexec(clipath + " listps")
for _, entry := range strings.Split(rawlist, "\n") {
eparts := strings.Split(entry, "\t")
if len(eparts) > 2 {
name := strings.TrimRight(eparts[1], "\x00")
val := strings.TrimRight(eparts[2], "\x00")
switch name { /* loading by name */
case "bootmode":
if val == "factory" {
bootmodefield.SetSelected("factory")
} else {
bootmodefield.SetSelected("normal")
}
case "imei1":
imei1field.SetText(val)
case "imei2":
imei2field.SetText(val)
case "psn":
psnfield.SetText(val)
case "dsn":
dsnfield.SetText(val)
case "wlan_mac1":
wlanmacfield.SetText(val)
case "bt_addr":
btmacfield.SetText(val)
case "pcbcfg":
pcbcfgfield.SetText(val)
case "devcfg":
devcfgfield.SetText(val)
case "sku":
skufield.SetText(val)
case "coo":
coofield.SetText(val)
case "dpc":
dpcfield.SetText(val)
case "wcc":
wccfield.SetText(val)
}
}
}
})
savebtn := widget.NewButton("Save devinfo", func() {
dialog.ShowConfirm("Confirm operation", "Overwrite devinfo partition?", func(choice bool) {
if choice == true {
var fieldset strings.Builder
fieldset.WriteString(" bootmode " + bootmodefield.Selected)
fieldset.WriteString(" imei1 " + imei1field.Text)
fieldset.WriteString(" imei2 " + imei2field.Text)
fieldset.WriteString(" psn " + psnfield.Text)
fieldset.WriteString(" dsn " + dsnfield.Text)
fieldset.WriteString(" wlan_mac1 " + wlanmacfield.Text)
fieldset.WriteString(" bt_addr " + btmacfield.Text)
fieldset.WriteString(" pcbcfg " + pcbcfgfield.Text)
fieldset.WriteString(" devcfg " + devcfgfield.Text)
fieldset.WriteString(" sku " + skufield.Text)
fieldset.WriteString(" coo " + coofield.Text)
fieldset.WriteString(" dpc " + dpcfield.Text)
fieldset.WriteString(" wcc " + wccfield.Text)
suexec(clipath + " setpstype bootmode DIUS")
res := suexec(clipath + " setpsval" + fieldset.String())
dialog.ShowInformation("Operation result", res, mainwin)
}
}, mainwin)
})
fixbtn := widget.NewButton("Fix IMEI CPSHA", func() {
dialog.ShowInformation("Operation result", suexec(clipath + " fiximeisha"), mainwin)
})
var tabs *container.AppTabs
randomimei1btn := widget.NewButton("Randomize IMEI 1", func() {
imei1field.SetText(genimei(tacprefixfield.Text))
tabs.SelectIndex(0)
})
randomimei2btn := widget.NewButton("Randomize IMEI 2", func() {
imei2field.SetText(genimei(tacprefixfield.Text))
tabs.SelectIndex(0)
})
randomwlanmacbtn := widget.NewButton("Randomize WLAN MAC", func() {
wlanmacfield.SetText(genmac(macprefixfield.Text))
tabs.SelectIndex(0)
})
randombtmacbtn := widget.NewButton("Randomize BT MAC", func() {
btmacfield.SetText(genmac(macprefixfield.Text))
tabs.SelectIndex(0)
})
atcmdrunbtn := widget.NewButton("Run AT command", func() {
atcmdres.SetText(suexec(clipath + " atcmd '" + atcmdfield.Text + "'"))
})
btnpanel := container.New(layout.NewGridLayout(2), loadbtn, savebtn)
/* program about message */
aboutmsg := `A universal tool to manipulate device-specific information for Tensor-based Google Pixel smartphones (root access required!)
Features:
* Edit main PS tags in the devinfo partition
* Switch the boot mode (normal or factory)
* Fix IMEI CPSHA after editing devinfo (requires the phone to be booted in the factory mode)
* Randomize IMEIs and MACs based on TACs or other prefixes
* Run arbitrary single-line AT commands
* Fully offline operation, no internet necessary
Works on Pixel 6, 6 Pro, 6a, 7, 7 Pro, 7a, Fold, 8, 8 Pro, 9, 9 Pro, 9 Pro XL, 9 Pro Fold, Pixel 10, Pixel 10 Pro
Get the source code at:
https://codeberg.org/luxferre/lexipwn
Created by Luxferre in 2024-2025, released into public domain with no warranties`
aboutlbl := widget.NewLabel(aboutmsg)
aboutlbl.Wrapping = fyne.TextWrapWord
/* layout and run */
tabs = container.NewAppTabs(
container.NewTabItem("Devinfo editor", container.NewVScroll(container.New(layout.NewVBoxLayout(),
widget.NewLabelWithStyle("lexipwn devinfo editor", fyne.TextAlignCenter, fyne.TextStyle{Bold:true}),
container.New(layout.NewGridLayout(2), bootmodelbl, bootmodefield),
fieldgrid, layout.NewSpacer(), btnpanel, fixbtn))),
container.NewTabItem("Utilities", container.NewVScroll(container.New(layout.NewVBoxLayout(),
widget.NewLabelWithStyle("IMEI/MAC generator", fyne.TextAlignCenter, fyne.TextStyle{Bold:true}),
container.New(layout.NewGridLayout(2), tacprefixlbl, tacprefixfield,
macprefixlbl, macprefixfield),
randomimei1btn, randomimei2btn, randomwlanmacbtn, randombtmacbtn,
layout.NewSpacer(),
widget.NewLabelWithStyle("AT command runner", fyne.TextAlignCenter, fyne.TextStyle{Bold:true}),
widget.NewLabel("Enter AT command (single line)"), atcmdfield, atcmdrunbtn,
widget.NewLabel("Result"), atcmdres))),
container.NewTabItem("About", container.NewVScroll(container.New(layout.NewVBoxLayout(),
layout.NewSpacer(),
widget.NewLabelWithStyle("About lexipwn", fyne.TextAlignCenter, fyne.TextStyle{Bold:true}),
aboutlbl,
layout.NewSpacer()))))
mainwin.SetContent(tabs)
/* emit the click to load devinfo */
loadbtn.Tapped(nil)
mainwin.ShowAndRun()
}