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

Implement fit.Label() and associated plumbing #1063

Closed
wants to merge 7 commits into from

Conversation

zachriggle
Copy link
Member

@zachriggle zachriggle commented Oct 30, 2017

Label Examples

Let's start by inspecting the three important attributes of a :class:.Label,
address, contents, and length.

>>> a = fit.Label("Static label contents")
>>> a.contents
"Static label contents"
>>> len(a) == len("Static label contents")
True
>>> a.address
0

When used inside of a fit() expression behind a lambda, these fields
can be automatically updated.

>>> a = fit.Label()
>>> offset = lambda: (len(a) / 4)
>>> contents = lambda: a("Dynamic contents.  Offset %i, Length %i" % (a.address, len(a)))
>>> fit({offset: contents})
'aaaabaaacDynamic contents.  Offset 9, Length 38'

After fit completes the packing, the values can be extracted from the label.

>>> a.contents, a.address, len(a)
('Dynamic contents.  Offset 9, Length 38', 9, 38)

The above example only makes use of one label, but you can build more complicated
constructs fairly easy.

>>> a = fit.Label()
>>> b = fit.Label()
>>> c = fit.Label()
>>> address = 0xdead0000
>>> build_fmtstr = lambda: '%%%d$n' % (1 + ((b.address - address) / 4))
>>> result = fit({
...     0:    lambda: "The format string is %d bytes long at %#x." % (len(build_fmtstr()), c.address),
...     0x40: lambda: a("Pretend this is some shellcode."),
...     0x80: lambda: [b("Pointer to a."), a.address, c(build_fmtstr())]
... }, address=address)
>>> print(hexdump(result))
00000000  54 68 65 20  66 6f 72 6d  61 74 20 73  74 72 69 6e  │The │form│at s│trin│
00000010  67 20 69 73  20 35 20 62  79 74 65 73  20 6c 6f 6e  │g is│ 5 b│ytes│ lon│
00000020  67 20 61 74  20 30 78 64  65 61 64 30  30 39 31 2e  │g at│ 0xd│ead0│091.│
00000030  6d 61 61 61  6e 61 61 61  6f 61 61 61  70 61 61 61  │maaa│naaa│oaaa│paaa│
00000040  50 72 65 74  65 6e 64 20  74 68 69 73  20 69 73 20  │Pret│end │this│ is │
00000050  73 6f 6d 65  20 73 68 65  6c 6c 63 6f  64 65 2e 61  │some│ she│llco│de.a│
00000060  79 61 61 61  7a 61 61 62  62 61 61 62  63 61 61 62  │yaaa│zaab│baab│caab│
00000070  64 61 61 62  65 61 61 62  66 61 61 62  67 61 61 62  │daab│eaab│faab│gaab│
00000080  50 6f 69 6e  74 65 72 20  74 6f 20 61  2e 40 00 ad  │Poin│ter │to a│.@··│
00000090  de 25 33 33  24 6e                                  │·%33│$n│
00000096

@zachriggle
Copy link
Member Author

zachriggle commented Oct 31, 2017

Interestingly, the output is wrong in the second case. The format string is not at offset 009e, but at 0091.

EDIT: Fixed

for arg in args:
address = address + out.tell()
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks wrong to me: Isn't out.tell() the amount of data written since the beginning, but address here is the address of the last written argument? I think it should be initial_address + out.tell() where initial_address is set to the value of the address parameter at the start of the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this explains the wrong output of the second sample.

Copy link
Contributor

@bennofs bennofs left a comment

Choose a reason for hiding this comment

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

I like it! 👍

for arg in args:
address = address + out.tell()

while isinstance(arg, type(lambda:0)):
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be better to check for callable here to support functions as well as lambdas?

Copy link
Contributor

Choose a reason for hiding this comment

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

Should give precendence to __flat_at__ / __flat__ in that case though

Copy link
Member Author

Choose a reason for hiding this comment

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

callable can't be used because we use __call__ on Label

Copy link
Contributor

Choose a reason for hiding this comment

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

It can be used if we check for __flat__ / __flat_at__ first, because Label has those.

Copy link
Member Author

Choose a reason for hiding this comment

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

We can't check for __flat__ etc. first, since we have to evaluate the callable / lambda before the check (or check again).

I added a special case check for FitLabel in 9358429

return int(self._address or 0)

@address.setter
def address(self, new):
Copy link
Contributor

Choose a reason for hiding this comment

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

Should there be a way to "manually" set the address of a label, without causing an exception?

Copy link
Member Author

Choose a reason for hiding this comment

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

Only when constructing the Label via __init__

for arg in args:
address = address + out.tell()
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this explains the wrong output of the second sample.

@bennofs
Copy link
Contributor

bennofs commented Aug 12, 2018

What's the state of this?

@zachriggle
Copy link
Member Author

Very stalled 😛!

If you're interested in continuing this PR, feel free to create a new branch from 9358429 and submit a new PR.

@heapcrash
Copy link
Collaborator

Closing this out since the PR is two+ years old and has merge conflicts.

Please rebase your changes on top of the current dev branch or create a new PR to get this merged.

@heapcrash heapcrash closed this Jun 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants