After Width: | Height: | Size: 588 KiB |
After Width: | Height: | Size: 207 KiB |
After Width: | Height: | Size: 565 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 425 KiB |
@ -0,0 +1,164 @@
|
||||
+++
|
||||
title = "Reverse engineering di un lettore di presenze"
|
||||
summary = "Step 1: incominciare a capire come funziona il tutto"
|
||||
date = "2024-04-28"
|
||||
|
||||
tags = ["Reverse Engineering", "Lettore di Presenze", "Decompilazione", "Codemerx"]
|
||||
categories = ["Progetti"]
|
||||
series = ["Lettore di presenze"]
|
||||
series_order = 1
|
||||
+++
|
||||
|
||||
Uno dei motivi per cui ho creato questo blog è per condividere le mie
|
||||
esperienze con altri pazzi entusiasti che adorano questo tipo di contenuti di
|
||||
nicchia come me.
|
||||
|
||||
In questa serie di articoli andrò a spiegare come ho eseguito il reverse
|
||||
engineering del protocollo di comunicazione usato tra un lettore di presenze ed
|
||||
il suo client (ovviamente creato solo per Windows) ed andremo a creare un
|
||||
client alternativo con [Rust](https://rust-lang.org/) e
|
||||
[Tauri](https://tauri.app/) per rimpiazzare quello proprietario.
|
||||
|
||||
![L'R701 di I.P.S. Informatica](images/01-r701.png "Ecco il lettore di presenze
|
||||
che andremo a reverse-enginerizzare")
|
||||
|
||||
## Un po' di background
|
||||
|
||||
Mio padre ha voluto aggiornare il vecchio lettore di presenze per la sua
|
||||
attività: è volato su Amazon e ha comprato
|
||||
l'[R701](https://ipsattendant.it/rilevatore-presenze-r701/) di [I.P.S.
|
||||
Informatica](https://ipsinformatica.info/).
|
||||
|
||||
A differenza del vecchio lettore, con questo i dipendenti possono registrare la
|
||||
loro presenza tramite PIN, impronta digitale o tramite un badge RFID, poi le
|
||||
registrazioni possono essere scaricate tramite il client ufficiale per Windows
|
||||
o tramite una chiavetta USB.
|
||||
|
||||
![Il vecchio lettore di presenze](images/02-old-clock.png "Il vecchio lettore
|
||||
di presenze assomigliava a questo")
|
||||
|
||||
Il problema è che il client, oltre ad essere installabile solo su Windows e
|
||||
richiedere un'account per eseguire azioni offline, non risponde ai requisiti
|
||||
dell'azienda.
|
||||
|
||||
Sarebbe gradito che ogni mese venisse fatto un report per ogni dipendente, con
|
||||
una tabella che permetta di vedere le ore lavorate ogni giorno. Invece il
|
||||
software ufficiale permette di scaricare solo una lista di presenze, senza
|
||||
alcun tipo di divisione per mese o per dipendente, e non permette di esportare
|
||||
il tutto in un file `.ods`.
|
||||
|
||||
Così, in pura modalità "[Stallman quando la nuova stampante Xerox si
|
||||
inceppa](https://oreilly.com/openbook/freedom/ch01.html)", ho deciso che la
|
||||
soluzione migliore è riscrivere il tutto in modo *open-source*.
|
||||
|
||||
## Dump delle registrazioni tramite USB
|
||||
|
||||
Come prima cosa ho provato a scaricare le registrazioni tramite una chiavetta
|
||||
USB, dato che questo metodo non necessita di un PC Windows. Così ho formattato
|
||||
una chiavetta in FAT32 e, dopo aver creato un utente di test e aver creato
|
||||
qualche registrazione, ho scaricato i dati sul mio laptop.
|
||||
|
||||
Una volta aperto il contenuto della chiavetta ho notato che il lettore ha
|
||||
creato due file:
|
||||
|
||||
* `~tmp.tmp`: che contiene la stringa `usb test!!` ripetuta 384 volte;
|
||||
* `AGLog_001.txt`: che contiene le registrazioni.
|
||||
|
||||
Credo che il file `~tmp.tmp` venga usato dal registratore solo per vedere se la
|
||||
chiavetta USB è scrivibile, quindi possoiamo ignorarlo.
|
||||
|
||||
Aprendo il file `AGLog_001.txt` possiamo andare ad intuire i vari campi che il
|
||||
lettore si salva in memoria:
|
||||
|
||||
```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` è l'ID della registrazione
|
||||
* `Mchn` è l'ID del registratore
|
||||
* `EnNo` è l'ID del dipendente che ha effettuato la registrazione
|
||||
(**En**ployee**No**mber ?)
|
||||
* `Name` è il nome del dipendente
|
||||
* `Mode` è la modalità con coi il dipendente ha registrato la presenza:
|
||||
* `33` è tramite l'impronta digitale
|
||||
* `34` è usando il PIN
|
||||
* `35` è con il badge
|
||||
* `IOMd` è il campo che simboleggia l'ingresso o l'uscita del dipendente
|
||||
(**I**n/**O**ut **M**o**d**e ?):
|
||||
* `0` è il primo ingresso
|
||||
* `1` è la prima uscita
|
||||
* `2` è il secondo ingresso
|
||||
* `3` è la seconda uscita
|
||||
* `Datetime` è la data e l'ora della registrazione
|
||||
|
||||
Considerando che ho registrato le presenze passando per tutte le modalità di
|
||||
ingresso e di uscita in ordine e che ho usato il PIN la prima volta, l'impronta
|
||||
digitale la seconda ed il badge le ultime due, possiamo ritenerci soddisfatti
|
||||
del risultato.
|
||||
|
||||
Potremmo addirittura scrivere un programma in Python che usi la libreria
|
||||
[csv](https://docs.python.org/3/library/csv.html) per estrarre i dati che ci
|
||||
servono da questo file.
|
||||
|
||||
Ma questo non sarebbe così interessante da essere un post sul mio blog. Non
|
||||
voglio entrare nel menù di amministrazione del dispositivo per poi premere in
|
||||
ordine i tasti `2`, `1` e `2` per fare il dump, poi prendere il file risultante
|
||||
e filtrarlo con uno script Python senza interfaccia grafica.
|
||||
|
||||
Voglio creare un programma che funzioni nativamente su Windows e Linux e che mi
|
||||
permetta di scaricare tutti i dati che mi interessano con un singolo click, già
|
||||
formattati correttamente.
|
||||
|
||||
Prima di tirare fuori [Wireshark](https://wireshark.org/) e provare a sniffare
|
||||
dei pacchetti però, voglio provare un'altra tecnica...
|
||||
|
||||
## Decompilare il client closed-source
|
||||
|
||||
Come disse una volta [un
|
||||
saggio](https://twitter.com/DebugPrivilege/status/1531661046238388226): "Tutto
|
||||
il codice è *open-source* se sai leggere Assembly".
|
||||
|
||||
Dato che la compagnia che ha scritto il codice è italiana e che il client
|
||||
funziona solo su Windows, c'è un alta probabilità che il codice sia stato
|
||||
scritto in C# su piattaforma .NET.
|
||||
|
||||
Se questo è il caso, dovrebbe essere abbastanza semplice ottenere il codice
|
||||
sorgente tramite un decompilatore come
|
||||
[CodemerxDecompile](https://decompiler.codemerx.com/).
|
||||
|
||||
Quindi ho creato una macchina virtuale con [Windows 10
|
||||
AME](https://archive.org/details/windows10-ame-21h1-2021-08-09/) e ho
|
||||
installato il client ufficiale alla [versione
|
||||
04.03.02](https://ipsattendant.it/download-programmi-e-manuali/).
|
||||
|
||||
{{< carousel images="images/03-official-client-installation/*"
|
||||
aspectRatio="16-9" interval="1000" >}}
|
||||
|
||||
Una volta installato il client ufficiale ho copiato la directory `C:\Program
|
||||
Files (x86)\ipsAttendant` sulla mia macchina Linux e l'ho aperta con
|
||||
CodemerxDecompile.
|
||||
|
||||
Come avevo previsto il codice è scritto in C#, quindi è facilmente leggibile.
|
||||
|
||||
![CodemerxDecompile](images/04-codemerx-decompile.png "Il codice
|
||||
dell'eseguibile aperto con CodemerxDecompile")
|
||||
|
||||
Cercando di qua e di là ho scoperto l'amara verità: dentro al file
|
||||
`Dichiarazioni.cs` sono presenti molti metodi interessanti, come
|
||||
`FK_ConnectNet()`. Questi metodi però sono tutti import da una libreria
|
||||
chiamata `FKAttend.dll`.
|
||||
|
||||
Cercando sul web, sembra che questa libreria sia in giro da molti anni e dubito
|
||||
altamente che l'abbia scritta la compagnia del lettore. Ho trovato anche [la
|
||||
documentazione ufficiale del
|
||||
DDL](</posts/2024/04/reverse-engineering-an-attendance-clock-part-1/FKAttend User's Manual.pdf>),
|
||||
ma nient'altro.
|
||||
|
||||
Dato che decompilare una libreria che manco il creatore ha avuto voglia di
|
||||
implementare da se non è una cosa che sono disposto a fare, nel prossimo
|
||||
articolo proveremo a fare il reverse engineering della comunicazione che
|
||||
avviene tra client e dispositivo.
|
@ -0,0 +1,158 @@
|
||||
+++
|
||||
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](</posts/2024/04/reverse-engineering-an-attendance-clock-part-1/FKAttend User's Manual.pdf>),
|
||||
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.
|