Author Topic: Help wanted reverse-engineering PIC16 assembly code  (Read 5619 times)

0 Members and 1 Guest are viewing this topic.

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Help wanted reverse-engineering PIC16 assembly code
« on: February 25, 2025, 08:51:39 am »
Hi guys,

I need some help reverse-engineering PIC16F1939 firmware. Even though I have over 2 decades of professional experience in embedded software development, my focus is mainly on U-Boot, Linux Kernel and applications and board support. PIC assembly is a whole different beast: I've been grinding my teeth on it for a few evenings, but I don't get much further.

Here's the situation:
I had the firmware extracted by 3rd party. They probably fuzzed the CPU. When I flash this firmware in an erased board using a PICkit, the board doesn't work entirely, but the functionality I'm looking for still does. So I think integrity of the extracted firmware is good enough.

I also own a MicroChip RealICE, and I have attached it to the board. However, debugging a binary without sources gets a bit weird in MPLab. I don't even know if I'm doing it right.

Going through the assembly is more tedious, but what I'm struggling most with, are the mnemonics for bank-switched registers: They seem to be largely incorrect, possibly because the active bank is unknown.

My goal is to figure out what happens with data retrieved from an I2C device. How exactly it is processed.

What I need is somebody who's a crack at PIC16 assembly, with experience in reverse engineering and familiar with the MPLab environment. Somebody who is capable and willing to help me hands-on, via remote desktop, for a price.

PM me if you're interested in helping me solve this puzzle.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6920
  • Country: es
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #1 on: February 25, 2025, 09:46:51 am »
Try decompiling it in Ghidra
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: MindBender

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2410
  • Country: ca
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #2 on: February 25, 2025, 04:59:13 pm »
I'll offer some help. I wrote my own disassembler which identifies all the functions and subroutines (targets of a call or goto) and tracks the pagesel register through the code flow, so it knows where the next call or goto is targeted. It also tracks the banksel register bits and decodes all SFP register access by name. It is a huge game changer for reverse engineering and I've used it more than once successfully. Of course it can't give logical names to subroutines or variables, but it does replace the hex values with ASCII names that you can search/replace-all as you figure stuff out.
One caveat is that it needs to be able to track code flow from the reset vector (usually address 0x0004 IIRC) otherwise it can't identify subroutines.
PM me the hex file and exact model of if the PIC and I'll run it through.
 
The following users thanked this post: MindBender, PeterPPP

Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 4804
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #3 on: February 25, 2025, 06:34:50 pm »
For 16F1xxx, mnemonics for instructions are only 47 and generally make sense.  The main exception raised by some people is "sublw,"  which translates to subtract WREG from a literal.  A feature of that series is the ability to operate directly on the w (working) register.  The name WREG (depending on how you set case sensitivity) rather than "w" must be used.  (Actually, I have never tired using just w so I can't be sure of that.)  Another thing to watch out for is the carry bit (STATUS,0).  Microchip calls it the carry/borrow bit.  Its behaviour makes sense, but some people get confused by its behavior during subtraction.  Its behavior also varies a little between 16Fxxx and 16F1xxx chips, so I always keep the 2-page instruction cheat sheet handy.

I second the need for a good disassembler.

Finally, bank shifting for the disassembler I use is crummy.  There is usually a warning to confirm the bank.  Does the code go past a single page significantly?  By that I mean are there calls and returns from another page (not to be confused with RAM banks)?  For most of my stuff, I put the ASCII character table on another page to avoid using code space and access it using indirect addressing (FSR0 and FSR1).  Those can reach any page and also allow you to access user RAM as a single, "linear RAM" space.

If there's a section that is particularly confusing, post it here, and we can try to help.   

EDIT: Very poor reader here and just noticed this,"willing to help me hands-on, via remote desktop, for a price."  Anything I offer is open source and priceless (i.e., free).
« Last Edit: February 25, 2025, 08:06:08 pm by jpanhalt »
 
The following users thanked this post: MindBender

Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 4804
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #4 on: February 25, 2025, 06:37:31 pm »
@macboy

I do not have your disassembler.  The one I use is quite old.  Are you willing to share a link?

John
 

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #5 on: February 26, 2025, 01:04:38 pm »
Try decompiling it in Ghidra
It has all the hallmarks of hand-coded assembly; I've tried Ghidra, but it gets confused easily.
 

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #6 on: February 26, 2025, 01:11:21 pm »
I'm using gpdasm. And it's a good one, because it produces the same result as MPLab X does. But it's a disassembler; All it does is disassemble machine language into assembly.
Finding functions and keeping track of which bank is selected, is a whole different story.
 

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #7 on: February 26, 2025, 01:22:06 pm »
I think the code I have is complete, starting from the reset vector. I've been going through the code manually, but that is a tedious job, and I'm stumbling onto all kinds of oddities, such as a function preceded by what looks like a jump table, utilized by that function, jumping back into the function. But also jumping to addresses outside that function in no used by that particular function, but that indicates its probably a resource shared with other functions.

Is your fancy disassembler with function-finding feature and bank selection tracker open source? And does it work for the 16F1939?
 

Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 4804
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #8 on: February 26, 2025, 03:22:22 pm »
Re: Keeping track of the Bank

If you can run it in a simulator, special function register BSR will tell you which bank it is in.  I still use MPASM in MPLab 8.92, so getting there is perhaps different.  For software debug, you have almost unlimited breakpoints.  For hardware simulation (ICD3 & MPLab 8.92), your chip allows 3 breakpoints.  Your more current software and hardware may allow even more.

How many instructions are there total?

 

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #9 on: February 26, 2025, 04:28:02 pm »
Re: Keeping track of the Bank

If you can run it in a simulator, special function register BSR will tell you which bank it is in.  I still use MPASM in MPLab 8.92, so getting there is perhaps different.  For software debug, you have almost unlimited breakpoints.  For hardware simulation (ICD3 & MPLab 8.92), your chip allows 3 breakpoints.  Your more current software and hardware may allow even more.
Unfortunately, it crashes in the simulator: It probably expect some pins to be at some level.
I do own a PICkit, a Real ICE and a PM3.
Quote
How many instructions are there total?
A little over 10,000. I'm going through the functions manually now, but there seem to be some errata in the datasheet: It contradicts itself in how many PCLATH bits are transferred to the PC register upon goto and call instructions. The operation part says "PCLATH<6:3> -> PC<14:11>", the description says "The upper bits of PC are loaded from PCLATH<4:3>." The first makes sense, for 4000-word program memory, but the latter is what everybody on the internet says it is. I'm surprised the datasheet of a chip this mature still contains sloppy errors like this.
« Last Edit: February 26, 2025, 04:32:39 pm by MindBender »
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2410
  • Country: ca
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #10 on: February 28, 2025, 03:01:48 pm »
Sorry about posting then ghosting. I was busy with work.
I have never open-sourced nor released my disassembler. Unfortunately, it only supports the baseline (12 bit instruction) and midrange (14 bit instr) PICs, but not the newer and better enhanced midrange, which the PIC16F1939 is. It could be modified to support that architecture, but I don't have any projects needing that right now so I don't have much incentive. As for specific device support, it uses the .inc file (e.g. P16F628A.inc) from MPLAB IDE to obtain the memory layout, SFR register names and bit names, etc., so it can support essentially any device in a supported architecture. That information is used during the disassembly process to name the registers and bits that are operands of instructions. I am not against open-sourcing the code, but I wrote it 10 years ago and I can hardly remember the state it's in, other than it is messy and full of FIXME comments.
 
The following users thanked this post: MindBender, jpanhalt

Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 4804
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #11 on: February 28, 2025, 03:19:56 pm »
Thanks for the response.  I am pretty much stuck on the enhanced mid-range.  They are pretty similar, but I do use the enhanced instructions for indirect addressing and linear RAM.

John
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6920
  • Country: es
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #12 on: February 28, 2025, 03:38:44 pm »
Can't be tthat messy if at least has comments!  :-+
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline abeyer

  • Frequent Contributor
  • **
  • Posts: 942
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #13 on: February 28, 2025, 08:34:30 pm »
Can't be tthat messy if at least has comments!  :-+

Code: [Select]
//  When I wrote this, only God and I understood what I was doing
//  Now, God only knows
 
The following users thanked this post: jpanhalt, Fire Doger, DavidAlfa

Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 4804
  • Country: us
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #14 on: February 28, 2025, 08:46:35 pm »
Hey, at 82, that struck too close to home. ;) 
 
The following users thanked this post: pardo-bsso

Offline MindBenderTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: nl
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #15 on: March 03, 2025, 03:03:18 pm »
Sorry about posting then ghosting. I was busy with work.
No worries!
Quote
I have never open-sourced nor released my disassembler. Unfortunately, it only supports the baseline (12 bit instruction) and midrange (14 bit instr) PICs, but not the newer and better enhanced midrange, which the PIC16F1939 is. It could be modified to support that architecture, but I don't have any projects needing that right now so I don't have much incentive. As for specific device support, it uses the .inc file (e.g. P16F628A.inc) from MPLAB IDE to obtain the memory layout, SFR register names and bit names, etc., so it can support essentially any device in a supported architecture. That information is used during the disassembly process to name the registers and bits that are operands of instructions. I am not against open-sourcing the code, but I wrote it 10 years ago and I can hardly remember the state it's in, other than it is messy and full of FIXME comments.
Well, I've been at it for a few evenings and a weekend, and I think I got what I need. Lessons learned:
1. Even though Ghidra supports the PIC16F19139, it does not properly recognize subroutines.
2. MPLab has a built-in disassembler, but the mnemonics it assigns to operants are not determined by tracing bank selection, and are misleading.
3. Gpdasm was a better option for me, because it doesn't resolve operants to presumed mnemonics: I prefer an opaque number over an erroneous name any time.
4. A disassembler does not attempt to find subroutines. That's a tedious manual job.

Thank for the help, guys!
 

Offline PeterPPP

  • Newbie
  • Posts: 1
  • Country: gb
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #16 on: November 10, 2025, 03:43:23 pm »
Hi all,

I'm pretty new to this but have a dump from a pic controller I need to decompile to find a certain code to change but I have no idea where to start. I have imported the code to but have no idea what I am looking at. i see @macboy you say you have made a decompiler. I was wondering if you could help maybe?
i would be really gratefull.
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2410
  • Country: ca
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #17 on: November 10, 2025, 04:17:50 pm »
Hi all,

I'm pretty new to this but have a dump from a pic controller I need to decompile to find a certain code to change but I have no idea where to start. I have imported the code to but have no idea what I am looking at. i see @macboy you say you have made a decompiler. I was wondering if you could help maybe?
i would be really gratefull.
I wrote a disassembler, not a decompiler. A decompiler would try to output high level code (often C language) which, when compiled, should do the same thing as the original machine code input. A disassembler outputs assembly code, which is more or less line-for-line the same as the machine code, but decoded and presented in a somewhat human readable format. My disassembler more advanced that most, in that it can find subroutines in the code and identify certain special registers, so the output has names of these registers, and generic names for the subroutines, instead of just hex addresses for both. The output is still assembly code, and bears no resemblance to a high level language like C.

Which PIC is your dump from? If my disassembler supports it then I can run it through. To successfully reverse engineer the code, you should also have a schematic of the board... at least everything that the PIC is connected to. This is necessary so that you can make some sense of the reads/writes to the I/O pins.
 

Offline zino

  • Newbie
  • Posts: 2
  • Country: se
Re: Help wanted reverse-engineering PIC16 assembly code
« Reply #18 on: September 26, 2026, 03:11:43 am »
I made a PIC16 dissassembler and decompiler plugin for Binary Ninja that has been doing good with everything I've thrown on it. It's available in the official plugin manager as a 3rd party release if you have a BN license. If you don't send me the binary and I'll have a look since it would be interesting to throw some more test-cases on it.

(Near enough necro-posting, sorry about that.)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->