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

Make unicorn be pull-based #97

Merged
merged 49 commits into from
Apr 3, 2017
Merged

Make unicorn be pull-based #97

merged 49 commits into from
Apr 3, 2017

Conversation

yan
Copy link
Contributor

@yan yan commented Mar 22, 2017

No description provided.

@yan yan force-pushed the dev-fix-unicorn-hax branch 2 times, most recently from fccc3f8 to 0e13c9c Compare March 27, 2017 13:54
Copy link
Contributor

@feliam feliam left a comment

Choose a reason for hiding this comment

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

Spectacularly awesome, true hero power!
I still need to review the _to_raise / _should_try_again logic.

try:
implementation = getattr(self, name)
except AttributeError as ae:
logger.debug("UNIMPLEMENTED INSTRUCTION: 0x%016x:\t%s\t%s\t%s", instruction.address, ' '.join(map(lambda x: '%02x'%x, instruction.bytes)), instruction.mnemonic, instruction.op_str)
# Make sure we're referencing the instruction look up
if name not in ae.message:
Copy link
Contributor

Choose a reason for hiding this comment

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

Or...
if hasattr(self.name): raise

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you have any strong thoughts on this? One argument for the current situation is not having an instruction is an exceptional situation, not normal control flow.

Copy link
Contributor

Choose a reason for hiding this comment

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

class B(object):
def two(self):
return 2

class A(object):
def one(self):
b = B()
return b.one()

a = A()
try :
a.one()
except Exception,e:
print "'one' in e:", 'one' in e.message
print e

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant :

if hasattr(self.name):

instead of:

if name not in ae.message:

@@ -403,6 +403,9 @@ def page_mask(self):
def maps(self):
return self._maps

def map_of_address(self, address):
Copy link
Contributor

Choose a reason for hiding this comment

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

Not used?
$ grep map_of_address . -Rn
./manticore/core/memory.py:406: def map_of_address(self, address):

self._emu = self._unicorn()

# Copy in the concrete values of all needed registers.
registers = set(self._cpu.canonical_registers)
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to at least document that ...
Ideally here we should only concretize registers that are going to be used/read. Otherwise we may destroy a lot of symbolic state that we don't need to.

There is some support for this in Capstone.instruction..regs_access()

Attempted here:
https://github.com/trailofbits/manticore/blob/dev-fix-unicorn/manticore/core/cpu/abstractcpu.py#L416-L432

val = self._cpu.read_register(reg)
if issymbolic(val):
from ..core.cpu.abstractcpu import ConcretizeRegister
raise ConcretizeRegister(reg, "Concretizing register for emulation.")
Copy link
Contributor

Choose a reason for hiding this comment

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

Lookout this will use default concretization policy (I think MINMAX?).
10 symbolic regs will spawn... a lot of states?
We should consider adding a policy='ONE' here.
Policy 'ONE' does not exist.

@@ -277,26 +277,26 @@ def __setstate__(self, state):
self._last_flags = state['_last_flags']
self._force_next = state['_force_next']

def _concretize_registers(cpu, instruction):
def _concretize_registers(self, instruction):
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not used, was left from your code. Okay to remove and then re-add once we capstone adds the functionality?

Copy link
Contributor

Choose a reason for hiding this comment

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

yes remove everywhere and lets re implement it when needed, if needed

@@ -544,18 +454,21 @@ class Syscall(CpuInterrupt):
def __init__(self):
super(Syscall, self).__init__("CPU Syscall")

# TODO(yan): Move this into State or a more appropriate location
_ValidPolicies = ['MINMAX', 'ALL', 'SAMPLED', 'ONE']
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes it sound like we need a base Concretize(Exception).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

# XXX(yan): We might need to raise here
pass

if logger.getEffectiveLevel() == logging.DEBUG:
Copy link
Contributor

Choose a reason for hiding this comment

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

logger.isEnabledFor() might be the preferred api here https://docs.python.org/2/howto/logging.html#optimization

uc.mem_map(address & ~0xFFF, 0x1000)

from ..core.cpu.abstractcpu import InvalidPCException
self._to_raise = InvalidPCException(address)
Copy link
Contributor

Choose a reason for hiding this comment

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

How do we know we are trying to execute from address?
Also normally provide the mapping for the current single instruction executed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That mapping gets added/memory brought in on line 191. And the offending address is a param to the hook

Copy link
Contributor

Choose a reason for hiding this comment

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

How can it be the case we are executing on not mapped memory if we provide a map for the initial emulation and we emulate only 1 instruction?

Also how do you discern READ from EXECUTE ? Can't that access be a buggy operand trying to access those arm special addresses ?

from ..core.cpu.abstractcpu import InvalidPCException
self._to_raise = InvalidPCException(address)
else:
self._to_raise = MemoryException("Can't read at", address)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't X86 et.al also raise an exception here? (I may be seeing the indentation wrong)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will, just the line above is a bit redundant. MemoryException will be raised on line 220 if we return False from here. I'll remove the above line during next cleanup.

self._should_try_again = False
return False

# XXX(yan): handle if this points to an incorrect mapping
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah no. Here is where we should check the mcore maps and raise if not mapped there.


try:
m = self._create_emulated_mapping(uc, address, size)
except:
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we filter for specific exceptions here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch (updating now)

).decode('hex')

# Map a TLS segment
self._arm_tls_memory = cpu.memory.mmap(None, 4, 'rw ')
Copy link
Contributor

Choose a reason for hiding this comment

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

it's not only tls in this memory, it's "kernel user helper memory" technically, so i think a rename would make it more accurate

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is only TLS memory though. What else can be in it?

Copy link
Contributor

Choose a reason for hiding this comment

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

sorry, my mistake, should have read more closely :(


def _step(self, instruction):
'''
A single attempt at execution an instruction.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo

if saved_PC == mu_pc:
self._cpu.PC = saved_PC + instruction.size

# Raise the exception from a hook that Uniocrn would have eaten
Copy link
Contributor

Choose a reason for hiding this comment

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

typo


#Unicorn hack. On single step unicorn wont advance the PC register
mu_pc = self.get_unicorn_pc()
if saved_PC == mu_pc:
Copy link
Contributor

Choose a reason for hiding this comment

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

A jump to self may be a problem here (if Unicorn actually wont update the pc for that one)

@yan yan merged commit 31b2979 into master Apr 3, 2017
@yan yan deleted the dev-fix-unicorn-hax branch April 3, 2017 20:00
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

3 participants