centos7 修改文件描述符_Frida之文件操作

在前面的文章中介绍了数据库的操作,这篇文章主要介绍文件的操作。

当你在使用程序的时候,可以动态修改程序的文件操作,其实是很恐怖的,比如,本来是往文件中写入100元钱,但是经过动态修改后变成了0元,据此可以脑洞大开一下。 @[toc]

基础概念

Linux下文件描述符

一个Linux进程启动后,会在内核空间创建一个PCB进程控制块,PCB是一个进程的私有财产。这个PCB中有一个已打开文件描述符表,记录着所有该进程打开的文件描述符以及对应的file结构体地址。

默认情况下,启动一个Linux进程后,会打开三个文件,分别是标准输入、标准输出、标准错误分别使用了0、1 、2号文件描述符。

当该进程使用函数open打开一个新的文件时,一般会在内核空间申请一个file结构体,并且把3号文件描述符对应的file指针指向file结构体。

977baa6f4f594af08dd5b6fb4f065f34.png

v-node table entry是虚拟文件系统对应的文件节点,i-node是磁盘文件系统对应的文件节点。通过这两个节点就能找到最终的磁盘文件。 举个例子:

#include #include #include int main(int argc,char *argv[]){   int fd = open("./1.c",O_RDWR);   printf("fd=%d",fd);}

程序运行结果是: fd=3

每一个进程只有一个process table entry,一般情况下默认使用 fd 0、fd1、fd2,新打开的文件1.c将使用fd 3,后续的文件描述符的值以此类推。

文件描述符含义0标准输入1标准输出2标准错误输出

JavaScript Promise对象

ECMAscript 6 原生提供了 Promise 对象。Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。

var myFirstPromise = new Promise(function(resolve, reject){    //当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)    //在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.    setTimeout(function(){        resolve("欢迎关注我的微信公众号:无情剑客!"); //代码正常执行!    }, 250);});myFirstPromise.then(function(successMessage){    //successMessage的值是上面调用resolve(...)方法传入的值.    //successMessage参数不一定非要是字符串类型,这里只是举个例子    document.write("Yay! " + successMessage);});

Promise简化了对error的处理,上面的代码我们也可以这样写:

promise.then(onFulfilled).catch(onRejected)

更多Promise的内容,后续会专门介绍。

Android Activity生命周期

为了在 Activity 生命周期的各个阶段之间导航转换,Activity 类提供六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()。当 Activity 进入新状态时,系统会调用其中每个回调。

30da34698709ee3d3f40de83a7d2e610.png

文件和流

文件File

  • new File(filePath, mode): open or create the file at filePath with the mode string specifying how it should be opened. For example "wb" to open the file for writing in binary mode (this is the same format as fopen() from the C standard library).
  • write(data): synchronously write data to the file, where data is either a string or a buffer as returned by NativePointer#readByteArray
  • flush(): flush any buffered data to the underlying file
  • close(): close the file. You should call this function when you’re done with the file unless you are fine with this happening when the object is garbage-collected or the script is unloaded. 举个例子,hook Activity的onResume函数,当回调onResume函数的时候,先通过File操作向'/data/data/com.lingpao.lpcf622b/files/chat/test.txt'这个文件中写入'hello world',最后调用系统的onResume回调。这里只是举例,实际情况可能需要保存一些重要的数据或者修改一些重要的数据。
import frida,sysdef on_message(message, data):    if message['type'] == 'send':        print(" {0}".format(message['payload']))    else:        print(message)passsession = frida.get_usb_device().attach("com.lingpao.lpcf622b")jscode = """if(Java.available){    Java.perform(function(){          var Activity = Java.use('android.app.Activity');         Activity.onResume.implementation = function () {                send('onResume() got called! ');                var file = new File('/data/data/com.lingpao.lpcf622b/files/chat/test.txt', 'wb');                file.write('hello world');                file.flush();                file.close();                this.onResume();         };    });}"""script = session.create_script(jscode)script.on("message", on_message)print(' Start attach')script.load()sys.stdin.read()

输入流InputStream

All methods are fully asynchronous and return Promise objects.

  • close(): close the stream, releasing resources related to it. Once the stream is closed, all other operations will fail. Closing a stream multiple times is allowed and will not result in an error.
  • read(size): read up to size bytes from the stream. The returned Promise receives an ArrayBuffer up to size bytes long. End of stream is signalled through an empty buffer.
  • readAll(size): keep reading from the stream until exactly size bytes have been consumed. The returned Promise receives an ArrayBuffer that is exactly size bytes long. Premature error or end of stream results in the Promise getting rejected with an error, where the Error object has a partialData property containing the incomplete data.

在类Unix系统中,获取输入流的方式:

  • new UnixInputStream(fd[, options]): create a new InputStream from the specified file descriptor fd. You may also supply an options object with autoClose set to true to make the stream close the underlying file descriptor when the stream is released, either through close() or future garbage-collection.

在Windwos平台下,获取输入流的方式:

  • new Win32InputStream(handle[, options]): create a new InputStream from the specified handle, which is a Windows HANDLE value. You may also supply an options object with autoClose set to true to make the stream close the underlying handle when the stream is released, either through close() or future garbage-collection.

Android是基于Linux系统的,所以属于类Unix系统,具体代码示例,在前面的文章中对Intercepter进行了介绍,这里对open函数进行替换,对打开的文件读取输入流。

var openPtr = Module.getExportByName(null, 'open');var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);Interceptor.replace(openPtr, new NativeCallback(function (pathPtr, flags) {  var path = pathPtr.readUtf8String();  console.log('Opening "' + path + '"');  var fd = open(pathPtr, flags); if (fd > 0){    var input = new UnixInputStream(fd);    var promise = input.read(1000);    promise.then(function(result){      console.log(' burning'+hexdump(result,{lenght:1000}));    }).catch(function(error){      console.log(' fail:'+error);    }); }  console.log('Got fd: ' + fd);  return fd;}, 'int', ['pointer', 'int']));

运行结果如下。

93dd2f4559d8422e3bcd2c44c266792a.png

输出流OutputStream

All methods are fully asynchronous and return Promise objects.

  • close(): close the stream, releasing resources related to it. Once the stream is closed, all other operations will fail. Closing a stream multiple times is allowed and will not result in an error.
  • write(data): try to write data to the stream. The data value is either an ArrayBuffer or an array of integers between 0 and 255. The returned Promise receives a Number specifying how many bytes of data were written to the stream.
  • writeAll(data): keep writing to the stream until all of data has been written. The data value is either an ArrayBuffer or an array of integers between 0 and 255. Premature error or end of stream results in an error, where the Error object has a partialSize property specifying how many bytes of data were written to the stream before the error occurred.
  • writeMemoryRegion(address, size): try to write size bytes to the stream, reading them from address, which is a NativePointer. The returned Promise receives a Number specifying how many bytes of data were written to the stream.

在类Unix系统中,获取输出流的方式:

  • new UnixOutputStream(fd[, options]): create a new OutputStream from the specified file descriptor fd. You may also supply an options object with autoClose set to true to make the stream close the underlying file descriptor when the stream is released, either through close() or future garbage-collection.

在Windwos平台下,获取输出流的方式:

  • new Win32OutputStream(handle[, options]): create a new OutputStream from the specified handle, which is a Windows HANDLE value. You may also supply an options object with autoClose set to true to make the stream close the underlying handle when the stream is released, either through close() or future garbage-collection.

具体使用,可参考InputStream的使用。

输入输出流

输入和输出都是相对的。高中物理讲过火车上的人,以车做参考系,人是静止的,但是如果以树做参考系人是运动的,那末输入输出的参考系是什么?

内存。往内存中写就是输入,从内存中向文件中写就是输出。

写在最后

预告一下,下篇Frida的文章说网络,网络的本质其实还是文件。

公众号

更多Frida相关的内容,欢饮关注我的微信公众号:无情剑客。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值