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

Provide an api to get raw data pointer from ArrayBuffer? #320

Closed
ChiChou opened this issue Jan 12, 2019 · 19 comments
Closed

Provide an api to get raw data pointer from ArrayBuffer? #320

ChiChou opened this issue Jan 12, 2019 · 19 comments

Comments

@ChiChou
Copy link
Contributor

ChiChou commented Jan 12, 2019

Some api only returns ArrayBuffer (like frida-fs).
When I have to pass them to ffi, looks like the best way is

const ffi = new NativeFunction(...);
const p = Memory.alloc(bytes.byteLength);
Memory.writeByteArray(p, bytes);
ffi(p, bytes.byteLength, ...);

That is an unnecessary extra memcpy.


Update: What I mean is something like std::string::data in C++.

@jmis1337
Copy link

jmis1337 commented Dec 4, 2019

can't you use type arrays like this?

new Uint8Array(bytes)[0]=0xff

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 5, 2019

can't you use type arrays like this?

new Uint8Array(bytes)[0]=0xff

You basically have no idea what I was talking about

@jmis1337
Copy link

jmis1337 commented Dec 5, 2019

nope you're probably right. but I guess the ticket was not clear. It looked like you are trying to read from an ArrayBuffer. That's how you read/write to an array buffer.
Just trying to help...

@Manouchehri
Copy link
Contributor

@ChiChou Hmm, would adding a Memory.sharedByteArray() that returns a SharedArrayBuffer work for your use case?

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 14, 2019

@Manouchehri Thanks a lot!

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 14, 2019

@Manouchehri @oleavr Oh wait. This is not what I mean.

I know nothing about internal implementation of v8 and Duktape (otherwise I'll submit a PR) but I guess there must be a vector in the backing store of an ArrayBuffer. What I need is to get the raw pointer of this continuous storage. If that's not clear, I mean something like std::string::data() in C++

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

@ChiChou That's exactly kind of what I implemented in a1034d3. You can now pass an ArrayBuffer to NativeFunction for any 'pointer' argument.

I also landed @Manouchehri's PR in eec44a1, which is a different thing: when you want to wrap an ArrayBuffer around a region of memory to easily peek/poke at it without going through read*()/write*() APIs for each access.

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

@ChiChou But thinking more about it, maybe we should just add a function to get the underlying pointer, and revert a1034d3. It's a bit more dangerous, but it's also more explicit... What do you think? Any good names come to mind?

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

A few ideas:

  • ptr(buf)
  • Memory.unwrap(buf)

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 14, 2019

a1034d3

@ChiChou That's exactly kind of what I implemented in a1034d3. You can now pass an ArrayBuffer to NativeFunction for any 'pointer' argument.

Yeah that works! Though an ArrayBuffer has different semantic to a pointer, but in most cases that a native function accepts a pointer and the length of buffer, this works perfectly.

So now the problem is how much the difference matters for frida scripts.

  • This NativePointer is out of Javascript engine's memory management. It could be dangling at any time
  • Anyway frida has arbitrary memory read/write, it is unsafe by design
  • With a NativePointer we can simply use .add to slice. But this doesn't seem so useful since we have ArrayBuffer.slice and eec44a1

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 14, 2019

nope you're probably right. but I guess the ticket was not clear. It looked like you are trying to read from an ArrayBuffer. That's how you read/write to an array buffer.
Just trying to help...

Anyway thank you for your reply. I've updated the thread for less confusion

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 14, 2019

A few ideas:

  • ptr(buf)
  • Memory.unwrap(buf)

One vote for Memory.unwrap. Or maybe ArrayBuffer.prototype.unwrap / data

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

@ChiChou Thanks! The only advantage of the implementation in current master is that it guarantees that the ArrayBuffer doesn't get GCed while the function call is happening, as the ArrayBuffer is on the JS stack for the duration of the function call. Because of this it makes it a bit harder to make a mistake. Like someone doing f(Memory.unwrap(makeBuffer())) where makeBuffer() does new ArrayBuffer() – and wondering why that pointer went bad in the middle of the function call. The disadvantage is that there's one extra check for any pointer value in NativeFunction calls. But there's always CModule for use-cases that involve hitting the same function over and over with minimal overhead.

And you have a good point regarding ArrayBuffer.slice. So maybe we should go for the current implementation.

I do like the "purer" nature of a separate function though. Hmm. Will need to sleep on this.

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

How about:

  • Memory.wrap(address: NativePointer, size: number): ArrayBuffer
  • Memory.unwrap(buffer: ArrayBuffer): NativePointer

So our current NativePointer.prototype.mapByteArray becomes Memory.wrap.

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

Hmm, leaning more towards ptr() and NativePointer.prototype.mapByteArray as the two counterparts. (Latter is how it's currently implemented in master.)

@oleavr
Copy link
Member

oleavr commented Dec 14, 2019

Some more ideas:

ptr(buf: ArrayBuffer): NativePointer;

p.castToBuffer(size: number): ArrayBuffer;
p.toLiveBuffer(size: number): ArrayBuffer;
p.toVolatileBuffer(size: number): ArrayBuffer;
p.toArrayBuffer(size: number): ArrayBuffer;

@oleavr
Copy link
Member

oleavr commented Dec 15, 2019

And a few more:

ArrayBuffer.wrap(address: NativePointer, size: number): ArrayBuffer;
ArrayBuffer.prototype.unwrap(): NativePointer;
ArrayBuffer.fromLiveMemory(address: NativePointer, size: number): ArrayBuffer;
// ArrayBuffer.fromMemoryNoCopy(address: NativePointer, size: number): ArrayBuffer;

ArrayBuffer.prototype.getBaseAddress(): NativePointer;

@oleavr
Copy link
Member

oleavr commented Dec 15, 2019

Think I'm going for these unless anyone has any objections:

ArrayBuffer.wrap(address: NativePointer, size: number): ArrayBuffer;
ArrayBuffer.prototype.unwrap(): NativePointer;

@ChiChou
Copy link
Contributor Author

ChiChou commented Dec 15, 2019

Think I'm going for these unless anyone has any objections:

ArrayBuffer.wrap(address: NativePointer, size: number): ArrayBuffer;
ArrayBuffer.prototype.unwrap(): NativePointer;

Cool!

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

No branches or pull requests

4 participants