Frida - hook android native C++ api - frida

Say android mediaserver has below API:
$ nm --demangle --dynamic libmediaplayerservice.so |grep setDataSourceAsync
0005c6f0 T android::NuPlayer::setDataSourceAsync(android::sp<android::DataSource> const&)
0005c008 T android::NuPlayer::setDataSourceAsync(android::sp<android::IStreamSource> const&)
0005c18c T android::NuPlayer::setDataSourceAsync(android::sp<android::IMediaHTTPService> const&, char const*, android::KeyedVector<android::String8, android::String8> const*)
0005c49c T android::NuPlayer::setDataSourceAsync(int, long long, long long)
$ nm -D libmediaplayerservice.so |grep setDataSourceAsync
0005c6f0 T _ZN7android8NuPlayer18setDataSourceAsyncERKNS_2spINS_10DataSourceEEE
0005c008 T _ZN7android8NuPlayer18setDataSourceAsyncERKNS_2spINS_13IStreamSourceEEE
0005c18c T _ZN7android8NuPlayer18setDataSourceAsyncERKNS_2spINS_17IMediaHTTPServiceEEEPKcPKNS_11KeyedVectorINS_7String8ES9_EE
0005c49c T _ZN7android8NuPlayer18setDataSourceAsyncEixx
Now I wish to hook the last one:
0005c49c T android::NuPlayer::setDataSourceAsync(int, long long, long long)
Below code will work but the API name is mangled:
var libname = "libmediaplayerservice.so";
var funame = "_ZN7android8NuPlayer18setDataSourceAsyncEixx";
Interceptor.attach(Module.getExportByName(libname, funame), {
onEnter: function(args) {
console.log("onEnter: call fun enter");
},
onLeave: function(retval) {
console.log("onLeave: call fun leave");
}
});
Two questions:
Is it possible to use demangled name just like below in javascript code:
android::NuPlayer::setDataSourceAsync(int, long long, long long)
The first argument int is a file descriptor just like open returned value. how can I use this fd to dump the file to disk in javascript?

1. Is it possible to use demangled name just like below in javascript code:
You will need to bind with Python, use send('mangle:' + func_name)
In python's side - on_message extract the func_name and mangle using subprocess to execute g++
def on_message(msg, _data):
if msg['type'] == 'send':
if msg['payload'].startswith('mangle:'):
# mangle
echo "class android{ void setDataSourceAsync(int, long long, long long) {}};void setDataSourceAsync(int,long long, long long){} " |\
g++ -x c++ -S - -o- |\
grep "^_.*:$" | sed -e 's/:$//'
It's tedious work ><
2. The first argument int is a file descriptor just like open returned value. how can I use this fd to dump the file to disk in
javascript?
You want to save every byte that goes into the fd?
To not interfere the app execution,
I suggest to use dup2, read from it and send to python's side or write to sdcard
var fopen = new NativeFunction(Module.findExportByName('libc.so', 'fopen'), 'pointer', ['pointer', 'pointer']);
var our_fd = fopen('/sdcard/tmpfile');
var dup2 = new NativeFunction(Module.findExportByName('libc.so', 'dup2'), 'pointer', ['pointer', 'pointer']);
dup2(fd, our_fd);
// use same technique to read from our_fd

Related

Passing strings to .wasm module

I've been stuck on this for a while now and I cannot seem to find good resources to my problem. I am coming from and "only C" background, so most of the web dev stuff is completely new for me.
I wrote a C function float editDistance(char *str1, char *str2) that returns the edit distance of 2 char arrays. Right now the goal is to successfully call this function from a JS environment.
After ensuring that the code works with the recommended Emscipten ccall method, I decided to move on. Now
I use Emscripten to compile the C code with flags -O3, -s WASM=1, -s EXPORTED_FUNCTIONS="['_editDistance']", and -s SIDE_MODULE=1 -s to Wasm. The JS code I'm trying to wrap around my WebAssembly is:
// Allocate memory for the wasm module to run in. (65536*256 bit)
let wasmMemory = new WebAssembly.Memory({
initial: 256
});
let info = {
env: {
abort: function() {},
memoryBase: 0,
tableBase: 0,
memory: wasmMemory,
table: new WebAssembly.Table({initial: 2, element: 'anyfunc'}),
}
}
// Define the strings
let str1 = "abcd";
let str2 = "abcd";
// Allocate memory on the wasm partition for the HEAPU8
let HEAPU8 = new Uint8Array(wasmMemory.buffer);
// Create the char arrays on the heap from the strings
let stackPtr = 0;
let str1Ptr = stackPtr;
stackPtr = stringToASCIIArray(str1, HEAPU8, stackPtr);
let str2Ptr = stackPtr;
stackPtr = stringToASCIIArray(str2, HEAPU8, stackPtr);
// Read the wasm file and instantiate it with the above environment setup. Then
// call the exported function with the string pointers.
let wasmBinaryFile = 'bin/edit_distanceW.wasm';
fetch(wasmBinaryFile, {credentials:"same-origin"})
.then((response) => response.arrayBuffer())
.then((binary) => WebAssembly.instantiate(binary,info))
.then((wa) => alert(wa.instance.exports._editDistance(str1Ptr, str2Ptr)));
// Converts a string to an ASCII byte array on the specified memory
function stringToASCIIArray(str, outU8Array, idx){
let length = str.length + 1;
let i;
for(i=0; i<length; i++){
outU8Array[idx+i] = str.charCodeAt(i);
}
outU8Array[idx+i]=0;
return (idx + length);
}
The generated wasm file when converted to wat demands these imports:
(import "env" "abort" (func (;0;) (type 0)))
(import "env" "memoryBase" (global (;0;) i32))
(import "env" "tableBase" (global (;1;) i32))
(import "env" "memory" (memory (;0;) 256))
(import "env" "table" (table (;0;) 2 anyfunc))
.. and exports these:
(export "__post_instantiate" (func 7))
(export "_editDistance" (func 9))
(export "runPostSets" (func 6))
(elem (;0;) (get_global 1) 8 1))
Now, when I test the code the strings are passed to the C module without a problem. A few function calls are even made on them (strLen) before things go south. In the C function there is this nasty nested loop that does the main computation, iterating thru a 2D array while reading the characters from the strings (C code just been ported from a paper with an ugly pseudo code, so pardon me the variable names):
do{
for(p=0; p<editDistance; p++){
// Do stuff
}
// Do more stuff
editDistance++;
} while(fkp[len2*2-len1][editDistance] != len1);
Before the function enters the for() loop, the module still has the strings on memory str1Ptr=0x00 and str2Ptr=0x05 with the correct length and content. On the contrary, immediately after entering the for() loop the memory gets overwritten by garbage (mostly 0s), corrupting the end result. I suspect some stack saving and restoration problems on the scope change, as the exact same code compiled to my PC using gcc works like a charm.
Any idea what setup I'm missing that hinders the correct completion of the C function?
If you are starting out you probably want to use the emscripten-generated JS glue. That is, don't use SIDE_MODULE=1 and instead output to a files calle .js. The emscripten compiler will then generate both a .js and a .wasm file. You can then include the .js file in your project and it will handle all the loading and setup for you.
If you try to load the wasm file yourself, you will need to do a lot of work to replicate the emscripten environment, which will require a lot of internal details of emscripten. Also, those internal details of subject to change when you update to the new version of emscripten so you are creating more work for yourself.

Automatic File Uploader to Website

I have a website with a form to upload files. I want to automatically sign in and upload image files once a changes are scene on my local folder on my computer. Can any guidance be provided in the matter.
As per my understanding, you can write a task for this purpose, which can run lets say every hour and check if any changes are made in directory then upload these files on you app.
I don't know what kind of system you are working on but you could do something like this. If you are on a linux system you could use the watch command to track the activity of the directory of choice. The what you could do is use something like Mechanize in a ruby script that gets triggered by the watch command that will then go and submit the form and upload the file for you by selecting the file with the latest creation date.
I realize that it says ruby on rails in the post, but this answer is just as legitimate as writing a solution in Ruby (and a bit easier/faster)
Using Qt C++ to do this, then you could do something like this:
(untested, you'll have to make adjustments for your exact situation)
Overview of Code:
Create a program that loops on a Timer every 20 minutes and goes through the entire directory that you specify with WATCH_DIR, and if it finds any files in that directory which were modified in between the time that the loop last ran (or after the program starts but before the first loop is run), then it uploads that exact file to whatever URL you specify with UPLOAD_URL
Then create a file called AutoUploader.pro and a file called main.cpp
AutoUploader.pro
QT += core network
QT -= gui
CONFIG += c++11
TARGET = AutoUploader
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
main.cpp
#include <QtCore/QCoreApplication>
#include <QtCore/qglobal.h>
#include <QDir>
#include <QDirIterator>
#include <QNetworkAccessManager>
#include <QTimer>
#include <QByteArray>
#include <QHash>
#define WATCH_DIR "/home/lenny/images"
#define UPLOAD_URL "http://127.0.0.1/upload.php"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MainLoop loop(WATCH_DIR);
return a.exec();
}
class MainLoop : public QObject {
Q_OBJECT
public:
MainLoop(QString _watch_directory = qApp->applicationDirPath()) {
watch_directory = _watch_directory;
// the ACTION="" part of the upload form
website_upload_url = UPLOAD_URL;
/* 20 minutes
20 * 60 * 1000 = num of milliseconds that makes up
20 mins = 1200000 ms */
QTimer::singleShot(1200000, this, SLOT(check_for_updates()));
/* this will stop any file modified before you ran this program from
being uploaded so it wont upload all of the files at runtime */
program_start_time = QDateTime::currentDateTime();
}
QDateTime program_start_time;
QString watch_directory;
QString website_upload_url;
// hash table to store all of the last modified times for each file
QHash<QString, QDateTime> last_modified_time;
~MainLoop() { qApp->exit(); }
public slots:
void check_for_updates() {
QDirIterator it(QDir(watch_directory));
/* loop through all file in directory */
while (it.hasNext()) {
QFileInfo info(it.next());
/* check to see if the files modified time is ahead of
program_start_time */
if (info.lastModified.msecsTo(program_start_time) < 1) {
upload_file(info.absoluteFilePath());
}
}
/* set program_start_time to the current time to catch stuff next
time around and then start a timer to repeat this command in
20 minutes */
program_start_time = QDateTime::currentDateTime();
QTimer::singleShot(1200000, this, SLOT(check_for_updates()));
}
/* upload file code came from
https://forum.qt.io/topic/11086/solved-qnetworkaccessmanager-uploading-files/2
*/
void upload_file(QString filename) {
QNetworkAccessManager *am = new QNetworkAccessManager(this);
QString path(filename);
// defined with UPLOAD_URL
QNetworkRequest request(QUrl(website_upload_url));
QString bound="margin"; //name of the boundary
//according to rfc 1867 we need to put this string here:
QByteArray data(QString("--" + bound + "\r\n").toAscii());
data.append("Content-Disposition: form-data; name=\"action\"\r\n\r\n");
data.append("upload.php\r\n");
data.append("--" + bound + "\r\n"); //according to rfc 1867
data.append(QString("Content-Disposition: form-data; name=\"uploaded\"; filename=\"%1\"\r\n").arg(QFileInfo(filename).fileName()));
data.append(QString("Content-Type: image/%1\r\n\r\n").arg(QFileInfo(filename).suffix())); //data type
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
return;
data.append(file.readAll()); //let's read the file
data.append("\r\n");
data.append("--" + bound + "--\r\n");
request.setRawHeader(QString("Content-Type").toAscii(),QString("multipart/form-data; boundary=" + bound).toAscii());
request.setRawHeader(QString("Content-Length").toAscii(), QString::number(data.length()).toAscii());
this->reply = am->post(request,data);
connect(this->reply, SIGNAL(finished()), this, SLOT(replyFinished()));
}
void replyFinished() {
/* perform some code here whenever a download finishes */
}
};
Before running this program, make sure to read through it completely and make the necessary changes by reading the comments and the post -- also you may have to install the qt framework depending on your platform
Anyways, the final step is to run qmake to create the project makefile and finally, make to build the binary.
Obviously the last steps are different depending on what system you are using.
... This program will continue to run... essentially forever until you close it.... uploading changed files every 20 minutes
Hope this helps...

Nodejs child_process spawn calling python script with sleep

I'm testing on nodejs child_process module to read the stdout from my python script. However, I noticed when my python emit message between every second. The nodejs callback can only collect the stdout at the end of the python script ends.
Python Script
import time
for i in range(0,5):
····print i
····time.sleep(0.5)
and the nodejs script is
var cp = require('child_process');
var spw = cp.spawn('python', ['tql.py']),
str = "";
spw.stdout.on('data', function (data) {
str+= data;
console.log(data);
});
spw.on('close', function (code) {
console.log(str);
});
spw.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
Instead of emit message each second, my program only calls the callback when the python script ends. Is there anything I need to know in order to achieve my goal?

How do I read an environment variable in Verilog/System Verilog?

How do I read an environment variable in Verilog ? (Running on a VCS simulator)
I am trying to accomplish
File=$fopen("$PATH/FileName","r");
$PATH is an environment variable.
You can simply use SystemVerilog DPI for getting environment.
And because getenv is a standard C library for every POSIX platform, so you do not need to implement your own getenv() equivalent function for the function definition again.
Example code in SV.
import "DPI-C" function string getenv(input string env_name);
module top;
initial begin
$write("env = %s\n", {getenv("HOME"), "/FileName"});
end
endmodule
Running
ncverilog -sv dpi.v
or
vcs -sverilog dpi.v
It will show
env = /home/user/FileName
And one more issue in your original question, PATH is a environment for executable search path and concatenate with ":" character. I think it should be an example here, not really "PATH" environment. Otherwise, your fopen file name could be "/bin:/usr/bin:/usr/local/bin/FileName", which is wrong.
You can use a simple PLI application to read an environment variable. Here's a sample, without any error checks:
#include <stdlib.h>
#include <string.h>
#include "vpi_user.h"
PLI_INT32 pli_getenv (PLI_BYTE8 * arg) {
vpiHandle tf_obj = vpi_handle (vpiSysTfCall, NULL);
vpiHandle arg_iter = vpi_iterate (vpiArgument, tf_obj);
vpiHandle arg1, arg2;
arg1 = vpi_scan (arg_iter);
arg2 = vpi_scan (arg_iter);
s_vpi_value vi, vo;
vi.format = vpiStringVal;
vpi_get_value (arg2, &vi);
vo.format = vpiStringVal;
vo.value.str = strdup (getenv (vi.value.str));
vpi_put_value (arg1, &vo, NULL, vpiNoDelay);
return 0;
}
The VCS documentation should explain how to link this into the simulator.
It is often simpler to use the Verilog preprocessor
File = $fopen(`PATH_FILENAME, "r");
Then invoke the simulator from your Makefile/shell script the specifying value to be substituted
$(SIM) -DPATH_FILENAME=\"$PATH/FileName\" blah.v ...
I use this with Icarus' iverilog often, vsim and friends probably support similar.
Quotes are escaped so that they are included in the substituted value, since the preprocessor will not substitute inside a literal value. For instance this combination does not work:
File = $fopen("`PATH_FILENAME", "r");
...
`$(SIM) -DPATH_FILENAME=$PATH/FileName blah.v ...`
Here I can see all answers, either they are using some DPI Or need some command line arguments. So I am sharing my answer with only SystemVerilog syntax. Answer is not specific to any simulator. But surely it is for Linux environment; for other OS we need to change $system commands.
We need to set this "logPath" system variable using some pre
processing script or by simulation script before we start our
simulation.
string myPath;
initial begin
//Writing System Variable To A File
$system("echo ${logPath} > logPath.txt");
//Opening that file and reading to a string variable
fh = $fopen ("./logPath.txt", "r");
void'($fscanf(fh,"%s",myPath));
//Appending File Name To That Path
myPath = {myPath,"/note.txt"};
//Closed and remove this temporary file
$fclose(fh);
$system("rm -rf logPath.txt");
//Open a file at the path that you have extracted from System Variable
//Do whatever you want now
fh = $fopen (myPath, "w");
repeat(10) begin
$fdisplay (fh, "%t %M: Write Line Number =|%0d| ", $time, i);
i++;
end
$fclose(fh);
end

Print list of ALL environment variables

I would like to print a list of all environment variables and their values. I searched the Stackoverflow and the following questions come close but don't answer me:
How to discover what is available in lua environment? (it's about Lua environment not the system environment variables)
Print all local variables accessible to the current scope in Lua (again about _G not the os environment variables)
http://www.lua.org/manual/5.1/manual.html#pdf-os.getenv (this is a good function but I have to know the name of the environment variable in order to call it)
Unlike C, Lua doesn't have envp** parameter that's passed to main() so I couldn't find a way to get a list of all environment variables. Does anybody know how I can get the list of the name and value of all environment variables?
Standard Lua functions are based on C-standard functions, and there is no C-standard function to get all the environment variables. Therefore, there is no Lua standard function to do it either.
You will have to use a module like luaex, which provides this functionality.
This code was extracted from an old POSIX binding.
static int Pgetenv(lua_State *L) /** getenv([name]) */
{
if (lua_isnone(L, 1))
{
extern char **environ;
char **e;
if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
for (e=environ; *e!=NULL; e++)
{
char *s=*e;
char *eq=strchr(s, '=');
if (eq==NULL) /* will this ever happen? */
{
lua_pushstring(L,s);
lua_pushboolean(L,0);
}
else
{
lua_pushlstring(L,s,eq-s);
lua_pushstring(L,eq+1);
}
lua_settable(L,-3);
}
}
else
lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
return 1;
}
You can install the lua-posix module. Alternatively, RedHat installations have POSIX routines built-in, but to enable them, you have to do a trick:
cd /usr/lib64/lua/5.1/
# (replace 5.1 with your version)
ln -s ../../librpmio.so.1 posix.so
# (replace the "1" as needed)
lua -lposix
> for i, s in pairs(posix.getenv()) do print(i,s,"\n") end
The trick is in creating a soft-link to the RPM's "io" directory and to naming the soft-link the same name of the library LUA will attempt to open. If you don't do this, you get:
./librpmio.so: undefined symbol: luaopen_librpmio
or similar.
local osEnv = {}
for line in io.popen("set"):lines() do
envName = line:match("^[^=]+")
osEnv[envName] = os.getenv(envName)
end
this would not work in some cases, like "no valid shell for the user running your app"
An easy 2 liner:
buf = io.popen("env", '*r')
output = buf:read('*a')
print(output) -- or do whatever

Resources