+++ title = "Reverse Engineering of an Attendance Reader" summary = "Step 1: Beginning to understand how everything works" date = "2024-04-28" tags = ["Reverse Engineering", "Attendance Reader", "Decompilation", "Codemerx"] categories = ["Projects"] series = ["Attendance Reader"] series_order = 1 +++ One of the reasons I created this blog is to share my experiences with other enthusiastic geeks who love this kind of niche content like me. In this series of articles, I will explain to you how I reverse-engineered the communication protocol used between an attendance reader and its (Windows-only) client, and we will create an alternative client with [Rust](https://rust-lang.org/) and [Tauri](https://tauri.app/) to replace the proprietary one. ![I.P.S. Informatica's R701](images/01-r701.png "Here's the attendance reader we're going to reverse-engineer") ## A bit of background My dad wanted to update the old attendance reader for his small business, so he went straight on Amazon and bought the [R701](https://ipsattendant.it/rilevatore-presenze-r701/) from [I.P.S. Informatica](https://ipsinformatica.info/). Unlike the old reader, with this one employees can record their presence via PIN, fingerprint, or RFID badge, then the records can be downloaded through the official Windows client or via a USB stick. ![The old attendance reader](images/02-old-clock.png "The old attendance reader looked something like this") The problem is that the client, besides being installable only on Windows and requiring an account to perform even offline actions, doesn't meet my dad's requirements. It would be appreciated if a report was generated every month for each employee, with a table showing the hours worked each day. Instead, the official software only allows you to download a list of presences, without any kind of division by month or employee, and it doesn't allow exporting everything to a `.ods` file. So, in pure "[Stallman when the new Xerox printer jams](https://oreilly.com/openbook/freedom/ch01.html)" mode, I decided that the best solution was to rewrite everything in an open-source way. ## Dumping the records via USB To begin, I tried to download the records using a USB stick, as this method doesn't require a Windows PC. I formatted a USB stick in FAT32, and after creating a test user and making a few records, I downloaded the data to my laptop. Once I opened the contents of the USB stick, I noticed that the reader had created two files: * `~tmp.tmp`: which contains the string `usb test!!` repeated 384 times; * `AGLog_001.txt`: which contains the records. I believe that the `~tmp.tmp` file is used by the reader only to check if the USB stick is writable, so we can ignore it. Opening the `AGLog_001.txt` file, we can start to look at the various fields that the reader stores in memory: ```csv No Mchn EnNo Name Mode IOMd DateTime 000001 1 000000001 test 34 0 2024/04/28 16:04:23 000002 1 000000001 test 33 1 2024/04/28 16:05:28 000003 1 000000001 test 35 2 2024/04/28 16:08:49 000004 1 000000001 test 35 3 2024/04/28 16:09:01 ``` * `No` is the record ID * `Mchn` is the reader ID * `EnNo` is the employee ID who made the record (**En**ployee **No**mber?) * `Name` is the employee's name * `Mode` is the method by which the employee recorded their presence: * `33` is via fingerprint * `34` is using a PIN * `35` is with the badge * `IOMd` is the field containing the employee entrance or exit (**I**n/**O**ut **M**o**d**e ?) * `0` is the first entrance * `1` is the first exit * `2` is the second entrancance * `3` is the second exit * `Datetime` is the date and time of the record Considering that I recorded the test records by passing through all the entrance and exit modes in order, using the PIN the first time, the fingerprint the second time, and the badge the last two times, we can be satisfied with the result. We could even write a Python program using the [csv](https://docs.python.org/3/library/csv.html) library to extract the data we need from this file. But this wouldn't be interesting enough to be a blog post. I don't want to enter the device's admin menu, press the `2`, `1`, and `2` keys in order to make a dump, then take the resulting file and filter it with a Python script without a graphical interface. I want to create a program that runs natively on Windows and Linux and allows me to download all the data I care about with a single click, in the format I need. Before pulling out [Wireshark](https://wireshark.org/) and trying to sniff some packets, I want to try another technique... ## Decompiling the closed-source client As [a wise man](https://twitter.com/DebugPrivilege/status/1531661046238388226) once said, "All source code is open source if you can read Assembly". Since the company that wrote the code is Italian and the client only works on Windows, there's a high chance the code is written in C# on the .NET platform. If this is the case, it should be pretty straightforward to get the source code through a decompiler like [CodemerxDecompile](https://decompiler.codemerx.com/). So I created a virtual machine with [Windows 10 AME](https://archive.org/details/windows10-ame-21h1-2021-08-09/) and installed the official client at [version 04.03.02](https://ipsattendant.it/download-programmi-e-manuali/). {{< carousel images="images/03-official-client-installation/*" aspectRatio="16-9" interval="1000" >}} Once I installed the official client, I copied the `C:\Program Files (x86)\ipsAttendant` directory onto my Linux machine and opened it with CodemerxDecompile. As I expected, the code is written in C#, so it's easily readable. ![CodemerxDecompile](images/04-codemerx-decompile.png "The executable code opened with CodemerxDecompile") Searching here and there, I found out the bitter truth: inside the `Dichiarazioni.cs` file, there are many interesting methods, such as `FK_ConnectNet()`. However, these methods are all imports from a library called `FKAttend.dll`. Searching the web, it seems this library has been around for many years, and I highly doubt the company that made the reader wrote it themselves. I also found the [official DDL documentation](), but nothing else. Since decompiling a library that even the creator didn't bother to implement themselves is not something I'm willing to do, in the next article, we will try to reverse-engineer the communication between the client and the device.