Repository: pwndbg/pwndbg

Issue:
Help: disasm with duplicate visual pointing references
I'm learning about RE and just find out pwndbg.

Using splitmind (saw it in FEATURES readme) with a custom setup of window/pane splitting, I got some "duplicate" visual references pointing to the same instruction in DISASM section.

I don't know if it's the right place to ask for help or not, sorry if it's not the right one   

![image](https://user-images.githubusercontent.com/6990857/80813910-4c0ae780-8ba1-11ea-9ef3-239a5153c32d.png)

I'm playing aroung with this:
https://crackmes.one/crackme/5d22b9d833c5d410dc4d0c9f

```
Gdb:       10.0.50.20200307-git
Python:    3.8.2 (default, Apr  8 2020, 14:31:25)  [GCC 9.3.0]
Pwndbg:    1.1.0 build: 3cf9b31
Capstone:  4.0.1024
Unicorn:   1.0.1
alacritty: 0.4.2
tmux:      3.1
zsh:       zsh 5.8 (x86_64-pc-linux-gnu)
OS:
DISTRIB_ID=ManjaroLinux
DISTRIB_RELEASE=20.0
DISTRIB_CODENAME=Lysia
DISTRIB_DESCRIPTION="Manjaro Linux"
```

My .gdbinit
```
source /home/lucasbertin/Projetos/OSS/pwndbg/gdbinit.py
set context-clear-screen on
set follow-fork-mode parent

source /home/lucasbertin/Projetos/OSS/splitmind/gdbinit.py
python
import splitmind
(splitmind.Mind()
  .tell_splitter(show_titles=True)
  .tell_splitter(set_title="Main")

  .right(display="backtrace", size="25%")

  .above(of="main", display="disasm", banner="top", size="85%")
  .right(of="disasm", display="legend")
  .below(of="legend", display="stack")

  .show("regs", on="legend")
  .below(of="backtrace", cmd='tty; tail -f /dev/null', clearing=False)
  .below(cmd="python3")
).build(nobanner=True)
end

set context-code-lines 30
set context-source-code-lines 30
set context-sections  "regs args code disasm stack backtrace"
```

Any tips or hints are welcome, thanks!!


Discussion:
pwndbg will emulate instructions and predict what branches will be taken in the future. Here the jump at `_dl_start+196` will be taken, so pwndbg predicts the future instructions to be executed - in this case a loop.

This can be seen here
https://github.com/pwndbg/pwndbg/blob/2a09b30649fe590a4f284c0dc9f484304074a829/pwndbg/commands/nearpc.py#L125-L129

So this might not be an issue at all depending on how you see it.
Thanks for your answer, so, if I got it correctly, what I saw is a feature that predict the next branches.
Looking at the code, there are some parameters for a lot of stuff... 
Is it possible to disable this emulation/prediction and, in the case, what kind of side effects of doing that?

Just asking a lot because I get a little bit lost when I see 5 green arrows pointing and, when step next, all arrows moves too.

Again, thanks for your time helping me.
See if this helps

https://github.com/pwndbg/pwndbg/blob/5849d27446f50280ed1ea81b98c40e0faff2bf06/pwndbg/commands/context.py#L416-L418

Try setting it to off
```
pwndbg> set emulate off
```
For more have a look at the `config` command
Tried the `set emulate off`, same green arrows around :disappointed: 
I'll search for config options later but, for now, thanks @sudhackar
Any other hint, please, let me know!
I was able to get what you wanted with `set emulate off` and this diff

```diff
diff --git a/pwndbg/commands/nearpc.py b/pwndbg/commands/nearpc.py
index f731dce..e8aff5c 100644
--- a/pwndbg/commands/nearpc.py
+++ b/pwndbg/commands/nearpc.py
@@ -94,7 +94,7 @@ def nearpc(pc=None, lines=None, to_string=False, emulate=False):
 
     #         for line in symtab.linetable():
     #             pc_to_linenos[line.pc].append(line.line)
-    instructions = pwndbg.disasm.near(pc, lines, emulate=emulate, show_prev_insns=not nearpc.repeat)
+    instructions = pwndbg.disasm.near(pc, lines, emulate=emulate, show_prev_insns=False)
 
     if pwndbg.memory.peek(pc) and not instructions:
         result.append(message.error('Invalid instructions at %#x' % pc))
diff --git a/pwndbg/disasm/__init__.py b/pwndbg/disasm/__init__.py
index c7a2a7b..f976f63 100644
--- a/pwndbg/disasm/__init__.py
+++ b/pwndbg/disasm/__init__.py
@@ -211,25 +211,25 @@ def near(address, instructions=1, emulate=False, show_prev_insns=True):
     total_instructions = 1 + (2*instructions)
 
     while insn and len(insns) < total_instructions:
-        target = insn.target
+        target = insn.address + insn.size
 
-        # Disable emulation if necessary
-        if emulate and set(insn.groups) & DO_NOT_EMULATE:
-            emulate = False
-            emu = None
+        # # Disable emulation if necessary
+        # if emulate and set(insn.groups) & DO_NOT_EMULATE:
+        #     emulate = False
+        #     emu = None
 
-        # If we initialized the emulator and emulation is still enabled, we can use it
-        # to figure out the next instruction.
-        if emu:
-            target_candidate, size_candidate = emu.single_step()
+        # # If we initialized the emulator and emulation is still enabled, we can use it
+        # # to figure out the next instruction.
+        # if emu:
+        #     target_candidate, size_candidate = emu.single_step()
 
-            if None not in (target_candidate, size_candidate):
-                target = target_candidate
+        #     if None not in (target_candidate, size_candidate):
+        #         target = target_candidate
 
-        # Continue disassembling at the *next* instruction unless we have emulated
-        # the path of execution.
-        elif target != pc:
-            target = insn.address + insn.size
+        # # Continue disassembling at the *next* instruction unless we have emulated
+        # # the path of execution.
+        # elif target != pc:
+        #     target = insn.address + insn.size
 
         insn = one(target)
         if insn:
```

Obviously I don't advise this as this may have unexpected results.
Hey,

> Tried the set emulate off, same green arrows around 😞

What do you mean by 'same green arrows around'? Does it give exactly the same output?

The `set emulate off` should disable this feature completely and you should see linear/flat disassembly instead. If it doesn't work, it is a bug.
@disconnect3d I couldn't get simply `set emulate off` to work too. Here's an example

![image](https://user-images.githubusercontent.com/10460978/80984187-299bf700-8e4b-11ea-9b73-e7f5333f7234.png)

@disconnect3d, yes, produced the same output.

Don't know if I did something wrong here but:
1- Started gdb with my binary
2- `set emulate off`
```
pwndbg> set emulate off
Set Unicorn emulation of code near the current instruction to False
```
3- Started my debug session

@sudhackar, thanks for sharing your results too!
I initially thought this could be a caching related bug, but it is not.

This it is not emulation here. This is our "disassembly enhancement display" feature.

The way it works is as follows:
- when we dissasembly instructions, we "enhance" them, via the `enhance` function: https://github.com/pwndbg/pwndbg/blob/d3ec217e602281cf8d66e2dd6d007c62cbe7fdfb/pwndbg/disasm/arch.py#L50-L59
- this is to improve view of the disassembled instructions
- the output we see is a consequence of the way the `enhance_next` works
- the `enhance_next` sets a `.next` and `.target` fields on an instruction: https://github.com/pwndbg/pwndbg/blob/d3ec217e602281cf8d66e2dd6d007c62cbe7fdfb/pwndbg/disasm/arch.py#L86-L121
- and so it itself resolves unconditional and conditional-but-known branches (jmp/call)
- so if there is a branch (jmp/call) for which we can get retrieve "what is the next/target instruction", the enhancement itself does it
- this fetching happens in the `next` method:
https://github.com/pwndbg/pwndbg/blob/d3ec217e602281cf8d66e2dd6d007c62cbe7fdfb/pwndbg/disasm/arch.py#L124-L164

So... the enhancement feature enhances the instruction to contain the information about the next instruction and a jump target, for a given jump/call instruction...

Now, if we would change the `instruction.target = self.next(instruction, call=True)` line to `instruction.target = None` OR change the `next` method  to just `return None`, this enhancement does not happen at all.

So in the end it seems this is not a bug, but I am not sure if we really want this behavior with `set emulate off`.

On the other hand, we could also have a `set enhance off`, and make it a right distinction on what is fetched from enhancing and what is fetched from emulation.

For now, I didn't touch emulation right now and I don't believe what exactly it did/helped with, but most likely, with calculating memory offsets or branch targets that we couldn't calculate "right away" without executing a set of instructions. (also, the emulation emulates only up to the next branch)

What do you think guys?
Also: @zachriggle @GrosQuildu @mzr @stnevans @anthraxx if you have any comments ;).
Ehh, I think I probably missed the main point here.

Regarding the visual duplicate of the "current instruction", what I marked on the screen below. This is indeed a small bug which we never worried about much.

We probably enhance current instruction no matter if it is displayed for the first time or any other time, and that's why we have the arrow there.

![image](https://user-images.githubusercontent.com/10009354/80997404-8c889080-8e41-11ea-97a7-acff080e1951.png)


Resolving patch:
diff --git a/pwndbg/commands/nearpc.py b/pwndbg/commands/nearpc.py
--- a/pwndbg/commands/nearpc.py
+++ b/pwndbg/commands/nearpc.py
@@ -119,13 +119,16 @@ def nearpc(pc=None, lines=None, to_string=False, emulate=False):
 
     prev = None
 
+    first_pc = True
+
     # Print out each instruction
     for address_str, symbol, instr in zip(addresses, symbols, instructions):
         asm    = D.instruction(instr)
         prefix_sign  = pwndbg.config.nearpc_prefix
 
         # Show prefix only on the specified address and don't show it while in repeat-mode
-        show_prefix = instr.address == pc and not nearpc.repeat
+        # or when showing current instruction for the second time
+        show_prefix = instr.address == pc and not nearpc.repeat and first_pc
         prefix = ' %s' % (prefix_sign if show_prefix else ' ' * len(prefix_sign))
         prefix = N.prefix(prefix)
 
@@ -138,10 +141,11 @@ def nearpc(pc=None, lines=None, to_string=False, emulate=False):
         if instr.address != pc or not pwndbg.config.highlight_pc or nearpc.repeat:
             address_str = N.address(address_str)
             symbol = N.symbol(symbol)
-        elif pwndbg.config.highlight_pc:
+        elif pwndbg.config.highlight_pc and first_pc:
             prefix = C.highlight(prefix)
             address_str = C.highlight(address_str)
             symbol = C.highlight(symbol)
+            first_pc = False
 
         line   = ' '.join((prefix, address_str, symbol, asm))
 


Test patch: