Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround issue with DebugSymbol #48

Closed
wants to merge 6 commits into from
Closed

Conversation

alvarofe
Copy link
Contributor

Dunno if this is the best solution but I noticed that when using dtf to trace calls instead of

write 1,"lala\no\n",5

I was getting

0x7fff98084910 1, "lala\no\n", 5

This can be a hassle when you are tracing many functions. DebugSymbol should be doing this, but as far I know it does not work so is just a dirty workaround.

If this is not good javascript just tell me quite noob tbh.

@alvarofe
Copy link
Contributor Author

Here the issue with DebugSymbol frida/frida-gum#186

@oleavr
Copy link
Member

oleavr commented Feb 19, 2017

Interesting. What does DebugSymbol.fromAddress(Module.findExportByName(null, 'write')) return if you run it in the Frida REPL on your system? (To install the REPL: pip install frida and run frida -p 0, which gives you a system-session meaning the JS gets executed inside of Frida itself, so you don't have to attach to any process.)

@alvarofe
Copy link
Contributor Author

alvarofe commented Feb 19, 2017

mm. It does work from REPL but it wasn't on r2frida side

[Local::ProcName::Tweetbot]-> DebugSymbol.fromAddress(Module.findExportByName(null, 'write'))
{
    "address": "0x7fff98084910",
    "fileName": "",
    "lineNumber": 0,
    "moduleName": "libsystem_kernel.dylib",
    "name": "write"
}

@alvarofe
Copy link
Contributor Author

air:r2 alvaro$ r2 frida://cat
Warning: r2frida cannot initialize mjolner
 -- Change the block size with 'b <block-size>'. In visual mode you can also enter radare2 command pressing the ':' key (like vi does)
[0x00000000]> \is write
0x7fff98084910
[0x00000000]> s 0x7fff98084910
[0x7fff98084910]> \dtf ^izi
true
[0x7fff98084910]> 0x7fff98084910 1,"lala\n",5

@alvarofe
Copy link
Contributor Author

alvarofe commented Feb 19, 2017

This from REPL fails

[Local::ProcName::cat]-> DebugSymbol.fromAddress(ptr(0x7fff98084910));
{
    "address": "0x7fff98084910",
    "fileName": null,
    "lineNumber": null,
    "moduleName": null,
    "name": null
}

@alvarofe
Copy link
Contributor Author

Is kind of random behavior. With Tweetbot works but with cat it doesn't.

http://asciinema.org/a/dfk9e430250x7gbm217zmcgch

@@ -961,7 +961,19 @@ function traceFormat(args) {
const traceOnEnter = format.indexOf('^') !== -1;
const traceBacktrace = format.indexOf('+') !== -1;

const at = DebugSymbol.fromAddress(ptr(address)) || '' + ptr(address);
var module = Process.enumerateModulesSync()[0].name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use const instead of var here

var module = Process.enumerateModulesSync()[0].name;
var imports = Module.enumerateImportsSync(module);
var at = '';
for (var index = 0; index < imports.length; index++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use let instead of var

@@ -961,7 +961,19 @@ function traceFormat(args) {
const traceOnEnter = format.indexOf('^') !== -1;
const traceBacktrace = format.indexOf('+') !== -1;

const at = DebugSymbol.fromAddress(ptr(address)) || '' + ptr(address);
var module = Process.enumerateModulesSync()[0].name;
var imports = Module.enumerateImportsSync(module);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imports are const

var module = Process.enumerateModulesSync()[0].name;
var imports = Module.enumerateImportsSync(module);
var at = '';
for (var index = 0; index < imports.length; index++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can iterate here with for (let import of imports) { if (imp.address === address) {

var imports = Module.enumerateImportsSync(module);
var at = '';
for (var index = 0; index < imports.length; index++) {
if (imports[index].address == address) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use ===

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of using == instead of === it does work. Maybe @oleavr that is the issue with DebugSymbol?

break;
}
}
if (at == '') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use ===, but better check for undefined. what if the import name is '' ? :P

@@ -961,7 +961,19 @@ function traceFormat(args) {
const traceOnEnter = format.indexOf('^') !== -1;
const traceBacktrace = format.indexOf('+') !== -1;

const at = DebugSymbol.fromAddress(ptr(address)) || '' + ptr(address);
var module = Process.enumerateModulesSync()[0].name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this logic into a separate function

if (at == '') {
'' + ptr(address);
}
//const at = DebugSymbol.fromAddress(ptr(address)) || '' + ptr(address);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove leftover

}
}
if (at == '') {
'' + ptr(address);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line does nothing

const module = Process.enumerateModulesSync()[0].name;
const imports = Module.enumerateImportsSync(module);
for (let imp of imports) {
if (imp.address == address) {
Copy link
Contributor Author

@alvarofe alvarofe Feb 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So == is needed to make a type conversion? If I use === it doesn't work

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also use compare method for native pointers/addresses

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Local::ProcName::cat]-> imports[0].address
"0x7fffb458f374"
[Local::ProcName::cat]-> imports[0].address.compare
function
[Local::ProcName::cat]-> imports[0].address.compare("0x0") // better to use `isNull()`
1
[Local::ProcName::cat]-> imports[0].address.compare(imports[0].address)
0
[Local::ProcName::cat]-> imports[0].address.compare(imports[1].address)
-1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare doesn't work.

[Local::ProcName::cat]-> imports[36].address.compare("0x7fff98084910")
0
[Local::ProcName::cat]-> imports[36].address == "0x7fff98084910"
true
[Local::ProcName::cat]-> imports[36]
{
    "address": "0x7fff98084910",
    "module": "/usr/lib/libSystem.B.dylib",
    "name": "write",
    "type": "function"
}

Javascript ¯\(ツ)

@oleavr
Copy link
Member

oleavr commented Feb 19, 2017

@alvarofe Yeah always use strict equality checking, the others shouldn't be used IMO. In this case though, the value is a NativePointer, so .equals() should be used. By the way, shouldn't this logic be a fallback when DebugSymbol fails?

@oleavr
Copy link
Member

oleavr commented Feb 19, 2017

Btw, if you feel like a little tour of non-strict equality craziness, check out this lightning talk:
https://www.destroyallsoftware.com/talks/wat

@alvarofe
Copy link
Contributor Author

I should review other places when DebugSymbol is used in case it fails

@radare
Copy link
Contributor

radare commented Feb 20, 2017 via email

@@ -91,6 +91,24 @@ const RTLD_GLOBAL = 0x8;
const RTLD_LAZY = 0x1;
const allocPool = {};

function nameFromAddress(address) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space between function name and opening parenthesis as per semistandard.

@@ -91,6 +91,24 @@ const RTLD_GLOBAL = 0x8;
const RTLD_LAZY = 0x1;
const allocPool = {};

function nameFromAddress(address) {
let at = DebugSymbol.fromAddress(ptr(address)).name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space and missing semicolon.

Copy link
Member

@oleavr oleavr Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By guaranteeing that this function is always called with a NativePointer (see suggestion below), we can drop ptr() here so it's just:

  let at = DebugSymbol.fromAddress(address).name;

@@ -960,8 +978,8 @@ function traceFormat(args) {
}
const traceOnEnter = format.indexOf('^') !== -1;
const traceBacktrace = format.indexOf('+') !== -1;
const at = nameFromAddress (address);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be simpler to always pass a NativePointer value to this function, by changing the else above from:

     var address = offset;

to:

     var address = ptr(offset);

(Note to self: we should refactor so offset is always a NativePointer.)

const module = Process.enumerateModulesSync()[0].name;
const imports = Module.enumerateImportsSync(module);
for (let imp of imports) {
if (imp.address.equals(ptr(address))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with this ptr().

}
}
if (at === null) {
at = '' + ptr(address);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this ptr().

@alvarofe
Copy link
Contributor Author

I had only time to update the PR. I couldn't look at other instances of DebugSymbol.

Regarding code style are you using https://github.com/Flet/semistandard ? just to make sure the next time I upload code in here.

Regarding compare @dweinstein you were right, I was using a string instead of NativePointer so my mistake.

@@ -91,6 +91,24 @@ const RTLD_GLOBAL = 0x8;
const RTLD_LAZY = 0x1;
const allocPool = {};

function nameFromAddress (address) {
let at = DebugSymbol.fromAddress(address).name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

}
}
if (at === null) {
at = '' + address;
Copy link
Member

@oleavr oleavr Feb 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at = address.toString(); would be clearer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is also done in several other places in this js, so i would go to change this in a separate pr

@@ -91,6 +91,24 @@ const RTLD_GLOBAL = 0x8;
const RTLD_LAZY = 0x1;
const allocPool = {};

function nameFromAddress (address) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if fromAddress() return null the .name will throw an exception that is not catched. i think that this code should be written in a different way. But Frida should already resolve those symbols . so it's a bug in Frida. Can you provide a reproducer? cc @oleavr

@trufae
Copy link
Member

trufae commented Feb 21, 2017

The problem here is that Frida is not exposing the address of the imports in the PLT/STUB inside the binary, so the symbols that hasnt been executed yet cannot be resolved. that's why you cant resolve write in cat because it's on hold in read.

One solution that comes to my mind will be to make Frida resolve the PLT symbols with the DebugSymbol API, or maybe provide an api to do that without having to iterate in js

@trufae
Copy link
Member

trufae commented Feb 21, 2017

nvm happens with read too.

@radare
Copy link
Contributor

radare commented Feb 22, 2017 via email

@alvarofe
Copy link
Contributor Author

I agree on that, do not have any clue about Frida's internals but If I can help to sort this out let me know. Ok to close this PR and move the issue into Frida? Where is this in handled in Frida within frida-gum?

@trufae
Copy link
Member

trufae commented Aug 28, 2017

i'll merge this workaround, and do some tweaks later. but the fix should be done in Frida, not in r2frida, as long as we have other workarounds for Frida in r2frida, it's ok for me to have this merged to make r2frida useful outside mac

@alvarofe
Copy link
Contributor Author

alvarofe commented Aug 28, 2017

I agree on that but Frida code is out of my reach for the time being, I asked where to open the issue, basically in which frida's repo. But if you want to include this temporary is ok for me

if (at === null) {
const module = Process.enumerateModulesSync()[0].name;
const imports = Module.enumerateImportsSync(module);
for (let imp of imports) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use Process.findModuleByAddress(address) to avoid having to iterate over all modules to find which import falls in this address

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, iterate over the Exports too

@trufae
Copy link
Member

trufae commented Aug 30, 2017

Fixed the comments and merged from 8e5401d

@trufae trufae closed this Aug 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants