Frida "invoke-virtual" method overload fails with "Error: expected a pointer" - android

I want to overload following method that I found by decompiling Android app with apktool:
invoke-virtual {v0, v4, v3}, Lokhttp3/aa$a;->b(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/aa$a;
Here is my Frida script:
Java.perform(function() {
var targetClass = Java.use("okhttp3.aa$a");
targetClass.b.overload("java.lang.String", "java.lang.String").implementation = function(a, b) {
console.log("str1:" + a);
console.log("str2:" + b);
return this.b(a, b);
}
});
Hook fails with:
[ERROR] Error: expected a pointer
at value (frida/runtime/core.js:170)
at At (frida/node_modules/frida-java-bridge/lib/android.js:879)
at activate (frida/node_modules/frida-java-bridge/lib/android.js:960)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/android.js:740)
at forEach (native)
at St (frida/node_modules/frida-java-bridge/lib/android.js:741)
at kt (frida/node_modules/frida-java-bridge/lib/android.js:732)
at vt (frida/node_modules/frida-java-bridge/lib/android.js:696)
at replace (frida/node_modules/frida-java-bridge/lib/android.js:1011)
at set (frida/node_modules/frida-java-bridge/lib/class-factory.js:1010)
at <anonymous> (/script2.js:3)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/vm.js:16)
at _performPendingVmOps (frida/node_modules/frida-java-bridge/index.js:238)
at <anonymous> (frida/node_modules/frida-java-bridge/index.js:213)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/vm.js:16)
at _performPendingVmOpsWhenReady (frida/node_modules/frida-java-bridge/index.js:232)
at perform (frida/node_modules/frida-java-bridge/index.js:192)
at <eval> (/script2.js:8)
How to correctly overload that method?
UPDATE
I figured out that error raised because I tried to load multiple scripts at once.
Is it possible?
import frida
import sys
package_name = "com.test.com"
def hook_okhttp_url():
hook_code = open('hook_okhttp_url.js').read()
return hook_code
def hook_cronet_header():
hook_code = open('hook_cronet_header.js').read()
return hook_code
def on_message(message, data):
if message['type'] == 'error':
print("[ERROR] " + message['stack'])
elif message['type'] == 'send':
print("[INFO] " + message['payload'])
else:
print(message)
device = frida.get_usb_device()
process = device.attach(package_name)
okhttp_script = process.create_script(hook_okhttp_url())
cronet_script = process.create_script(hook_cronet_header())
okhttp_script.on('message', on_message)
cronet_script.on('message', on_message)
print('[*] Running Hook Test ...')
okhttp_script.load()
cronet_script.load()
sys.stdin.read()
I figured out that error raised because I tried to load multiple scripts at once.
Is it possible?

When it comes to overloaded methods I prefer to hook and call method this way (as it makes less problems):
Java.perform(function() {
const targetClass = Java.use("okhttp3.aa$a");
const targetMethod = targetClass.b.overload("java.lang.String", "java.lang.String");
targetMethod.implementation = function(a, b) {
console.log("str1:" + a);
console.log("str2:" + b);
return targetMethod.call(this, a, b);
}
});

Ended up with concatenating all js files with my hooks into one.

Related

java.lang.ClassNotFoundException on frida

I am trying to hook function of android messaging application.
I run frida hook script. then I get a following error:
Error: java.lang.ClassNotFoundException: Didn't find class "i0.a.a.a.e3.z" on path: DexPathList[[/data/app/xxxxx==/base.apk]]
In Jadx-Gui, base.apk is decompiled as follows
package i0.a.a.a.e3;
/* loaded from: classes5.dex */
public final class z {
}
script is as follows
let z = Java.use("i0.a.a.a.e3.z");
How can I solve this error?
Try running your hook inside the Java.perform() method of Frida.
Java.perform(function() {
let z = Java.use("i0.a.a.a.e3.z");
z["somefunction"].implementation = function (str) {
console.log('somefunctionis called' + ', ' + 'str: ' + str);
let ret = this.somefunction(str);
console.log('somefunctionret value is ' + ret);
return ret;
};
})
It solved my problem that was similar to yours.

how to implement client listener in Android using golang object?

Problem description:
I am working on a small project in which i need to port the existing mqtt client library from Golang to Android.
I found using gomobile repository as an option to prevent duplicating the same functionality in different programming languages (GO and Java).
To use this library we have two different options:
Design the android app purely in Go and use "gomobile -build" to generate an APK file. An APK file then can be loaded to android device or emulator using adb tool.
Implement some functionality and then bind them into existing Android project using "gomobile -bind". With this option there are some restriction for conversion and building Golang objects.
For my case I plan to pick the second option. Also trying to convert the following small sample GO implementation to Android (borrowed from here).
package main
import (
"fmt"
mqtt "github.com/eclipse/paho.mqtt.golang"
"log"
"time"
)
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}
var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
fmt.Println("Connected")
}
var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
fmt.Printf("Connect lost: %v", err)
}
func main() {
var broker = "broker.emqx.io"
var port = 1883
opts := mqtt.NewClientOptions()
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
opts.SetClientID("go_mqtt_client")
opts.SetUsername("emqx")
opts.SetPassword("public")
opts.SetDefaultPublishHandler(messagePubHandler)
opts.OnConnect = connectHandler
opts.OnConnectionLost = connectLostHandler
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
sub(client)
publish(client)
client.Disconnect(250)
}
func publish(client mqtt.Client) {
num := 10
for i := 0; i < num; i++ {
text := fmt.Sprintf("Message %d", i)
token := client.Publish("topic/test", 0, false, text)
token.Wait()
time.Sleep(time.Second)
}
}
func sub(client mqtt.Client) {
topic := "topic/test"
token := client.Subscribe(topic, 1, nil)
token.Wait()
fmt.Printf("Subscribed to topic: %s", topic)
}
My Question:
After converting the sample code, i am not sure how i can implement the listener side.
the probelm is that "gomobile -bind" cannot convert all user data types (i.e client into Java).
I can implement the connect, subscribe, and publish, but not the listener one (in other words, the "opts.SetDefaultPublishHandler(messagePubHandler)" is not repeatedly working when i call the corresponding method in Android)
Any suggestion?
This is what is tried, but it does not work
var Options *mqtt.ClientOptions
var ReceivedMsg string
func AddBroker(broker string, port int) {
Options = mqtt.NewClientOptions()
Options.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
}
var MessagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
ReceivedMsg = " Message " + string(msg.Payload()) + " received on topic" + msg.Topic()
fmt.Printf(ReceivedMsg)
}
func Listener(clientId string) {
Options.SetClientID(clientId)
Options.SetDefaultPublishHandler(MessagePubHandler)
Options.OnConnect = ConnectHandler
Options.OnConnectionLost = ConnectionLostHandler
}

frida hook android system_server report Error: expected a pointer

I am trying to hook android11 system_server On linux. frida version is 14.2.13.
The script as below:
Java.perform(function () {
var clazz = Java.use("com.android.server.policy.PhoneWindowManager")
var func = "powerPress"
console.log(func)
clazz[func].implementation = function (arg1,arg2,arg3) {
console.log("Enter " + func + " " + arg1,arg2,arg3)
this[func](arg1,arg2,arg3)
}
}
)
The command to launch frida:
$ frida -U -l script.js -p $(adb shell pidof system_server)
____
/ _ | Frida 14.2.13 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Attaching...
powerPress
Error: expected a pointer
at value (frida/runtime/core.js:170)
at yt (frida/node_modules/frida-java-bridge/lib/android.js:889)
at activate (frida/node_modules/frida-java-bridge/lib/android.js:970)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/android.js:745)
at forEach (native)
at St (frida/node_modules/frida-java-bridge/lib/android.js:746)
at Et (frida/node_modules/frida-java-bridge/lib/android.js:737)
at vt (frida/node_modules/frida-java-bridge/lib/android.js:696)
at replace (frida/node_modules/frida-java-bridge/lib/android.js:1021)
at set (frida/node_modules/frida-java-bridge/lib/class-factory.js:1010)
at set (frida/node_modules/frida-java-bridge/lib/class-factory.js:925)
at <anonymous> (/script.js:4)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/vm.js:16)
at _performPendingVmOps (frida/node_modules/frida-java-bridge/index.js:238)
at <anonymous> (frida/node_modules/frida-java-bridge/index.js:213)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/vm.js:16)
at _performPendingVmOpsWhenReady (frida/node_modules/frida-java-bridge/index.js:232)
at perform (frida/node_modules/frida-java-bridge/index.js:192)
at <eval> (/script.js:10)
[device]-> Enter powerPress 44442 true 1
Enter powerPress 46290 true 1
Enter powerPress 52580 true 1
Enter powerPress 53910 true 1
The hook looks like work but exception happen!
this is not how you would normaly hook a function have a look on the official docs
https://frida.re/docs/android/
try this instead
Java.perform(function () {
Java.Use("com.android.server.policy.PhoneWindowManager").powerPress.overload().implementation = function(arg1, arg2, arg3){
console.log("Enter Powerpress :" + arg1,arg2,arg3);
Java.Use("com.android.server.policy.PhoneWindowManager").powerPress.overload().call(this, arg1,arg2,arg3);
}
)
guessing that you are passing args you will need to specify the type of each arg and pass it to the overload function launch the script it will give you a error and copy paste the correct function overload on both the call line and the implementation line
If the method no overrides, then no need to add overload.
Use apply to call original function.
Java.perform(function () {
var clazz = Java.use("com.android.server.policy.PhoneWindowManager")
var func = "powerPress"
console.log(func)
clazz[func].implementation = function (arg1,arg2,arg3) {
console.log("Enter " + func + " " + arg1,arg2,arg3)
this[func].apply(this,[arg1,arg2,arg3])
//or this[func].call(this,arg1,arg2,arg3)
}
}
)

How to query all connected devices in build.gradle?

I am trying to write a task in build.gradle that executes shell commands on all connected devices. However, when I run my task, I get the notorious 'multiple devices connected' error.
task(myTask, type: Exec) {
doFirst {
println 'myTask'
commandLine 'adb', 'shell', 'my command'
}
}
This is understandable, because I did not specify which device to run on with -s. However, I noticed that the installDebug task will execute its commands on all connected devices (install debug .apk on all devices).
Is there an API in the android plugin that returns a collection of devices IDs that I can iterate over?
Yes.You can check the Android Gradle Plugin source here, where you will find the following:
import com.android.ddmlib.AndroidDebugBridge
import com.android.ddmlib.IDevice
// ...
AndroidDebugBridge.initIfNeeded(false /*clientSupport*/)
AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(android.getAdbExe().absolutePath,
false /*forceNewBridge*/)
long timeOut = 30000 // 30 sec
int sleepTime = 1000
while (!bridge.hasInitialDeviceList() && timeOut > 0) {
sleep(sleepTime)
timeOut -= sleepTime
}
if (timeOut <= 0 && !bridge.hasInitialDeviceList()) {
throw new RuntimeException("Timeout getting device list.", null)
}
IDevice[] devices = bridge.devices
if (devices.length == 0) {
throw new RuntimeException("No connected devices!", null)
}
File destination = project.file("$project.buildDir/outputs/screenshots")
delete destination
for (IDevice device : devices) {
// iterate over your devices here ;)
}
Also you will notice that there is a getter for adb as well that you can use in the loop from above:
project.exec {
executable = android.getAdbExe()
args '-s'
args "$device.serialNumber"
}
Old thread, but maybe it helps someone at some point.
As David Medenjak already mentioned the android.ddmlib is the solution.
You can use it like the following:
In yourscript.gradle:
import com.android.ddmlib.AndroidDebugBridge
import com.android.ddmlib.IDevice
import com.android.ddmlib.NullOutputReceiver
task pressPower {
description = "Press the power button of a device using the adb."
AndroidDebugBridge.initIfNeeded(false)
def bridge = AndroidDebugBridge.createBridge(android.adbExecutable.path, false)
doLast {
bridge.devices.each {
it.executeShellCommand("input keyevent 26", NullOutputReceiver.receiver)
}
}
}
In which "input keyevent 26" corresponds to the shell command ./adb shell input keyevent 26.
If you want to work with the output of the shell you can use the CollectingOutputReceiver like below:
import com.android.ddmlib.AndroidDebugBridge
import com.android.ddmlib.IDevice
import com.android.ddmlib.CollectingOutputReceiver
task getAnimationValue {
description = "Get the Value for the window animation scale."
AndroidDebugBridge.initIfNeeded(false)
def bridge = AndroidDebugBridge.createBridge(android.adbExecutable.path, false)
def receiver = CollectingOutputReceiver.newInstance()
doLast{
bridge.devices.each {
it.executeShellCommand("settings get global window_animation_scale", receiver)
println "Value: ${receiver.getOutput()}"
}
}
}
The task prints the value for the window animation scale gathered by receiver.getOutput().

get response from cmd with visual basic

I made an application in Visual Basic that opens cmd and transfer files to an Android receiver over VPN. it works fine but how do i get the response from cmd to check whether the transfer was succesful or not?
sample codes
Public Class Form1
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
Shell("cmd.exe /k" + "adb push C:\Users\user\Desktop\Newfolder\1.png /sdcard/test")
End Sub
Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
Shell("adb connect " + TextBox1.Text)
btnSend.Enabled = True
btnConnect.Enabled = False
End Sub
End Class
I am assuming that you are wanting to get the return code or std output of the adb commands. Either way you are going to need to start your own process instead of using the Shell command because:
A process can return an exit code when it terminates. However, you cannot use Shell to retrieve this exit code, because Shell returns zero if it waits for termination, and also because the process runs in a different object from Shell. From http://msdn.microsoft.com/en-us/library/xe736fyk%28v=vs.90%29.aspx
the link will show you how to set up a processes that returns an exit code. The relevant code is
Dim procID As Integer
Dim newProc As Diagnostics.Process
newProc = Diagnostics.Process.Start("C:\WINDOWS\NOTEPAD.EXE")
procID = newProc.Id
newProc.WaitForExit()
Dim procEC As Integer = -1
If newProc.HasExited Then
procEC = newProc.ExitCode
End If
MsgBox("Process with ID " & CStr(ProcID) & _
" terminated with exit code " & CStr(procEC))
if you are wanting not the return code, but the standard output from the program, then according to http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.process.standardoutput?cs-save-lang=1&cs-lang=vb#code-snippet-4
you can do that via this code snippet:
Imports System
Imports System.IO
Imports System.Diagnostics
Class IORedirExample
Public Shared Sub Main()
Dim args() As String = Environment.GetCommandLineArgs()
If args.Length > 1
' This is the code for the spawned process'
Console.WriteLine("Hello from the redirected process!")
Else
' This is the code for the base process '
Dim myProcess As New Process()
' Start a new instance of this program but specify the spawned version. '
Dim myProcessStartInfo As New ProcessStartInfo(args(0), "spawn")
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.RedirectStandardOutput = True
myProcess.StartInfo = myProcessStartInfo
myProcess.Start()
Dim myStreamReader As StreamReader = myProcess.StandardOutput
' Read the standard output of the spawned process. '
Dim myString As String = myStreamReader.ReadLine()
Console.WriteLine(myString)
myProcess.WaitForExit()
myProcess.Close()
End If
End Sub
End Class
when you are trying this out yourself, remember that you must include the
myProcessStartInfo.UseShellExecute = False
line as well.

Categories

Resources