Honestly, I don't know its exact name, but I would call it "shifted pointer". This technique is quite common, at least in copy protection schemes.
In short: while writing a value into global memory you use an address, but by reading you use a sum of (other) addresses, or maybe a difference. The goal is to hide a real address from a reverse engineer who debugs the code or exploring it in IDA (or another disassembler).
This can be a nuisance.
#include <stdio.h> // 64KiB, but it's OK unsigned char secret_array[0x10000]; void check_lic_key() { // pretend, lic_check has failed secret_array[0x6123]=1; // 1 mean failed // printf ("check failed\n"); // exit(0); a cracker may patch here // or put there another value if check is succeeded // secret_array[0x6123]=0; }; unsigned char get_byte_at_0x6000(unsigned char *a) { return *(a+0x6000); }; void check_again() { if (get_byte_at_0x6000(secret_array+0x123)==1) { // do something mean (add watermark maybe) or report error: printf ("check failed\n"); } else { // proceed further }; }; int main() { // at start: check_lic_key(); // do something // ... and while in some very critical part: check_again(); };
If compiled by non-optimizing MSVC 2015:
_check_lic_key proc near push ebp mov ebp, esp mov eax, 1 imul ecx, eax, 6123h mov _secret_array[ecx], 1 pop ebp retn _check_lic_key endp ; char __cdecl get_byte_at_0x6000(char *a) _get_byte_at_0x6000 proc near a = dword ptr 8 push ebp mov ebp, esp mov eax, [ebp+a] mov al, [eax+6000h] pop ebp retn _get_byte_at_0x6000 endp _check_again proc near push ebp mov ebp, esp push offset point_passed_to_get_byte_at_0x6000 ; a call j__get_byte_at_0x6000 add esp, 4 movzx eax, al cmp eax, 1 jnz short loc_406735 push offset _Format ; "check failed\n" call j__printf add esp, 4 loc_406735: ; CODE XREF: _check_again+16 pop ebp retn _check_again endp .data:0045F5C0 ; char secret_array[65536] .data:0045F5C0 _secret_array db 123h dup(?) ; DATA XREF: _check_lic_key+E .data:0045F6E3 ; char point_passed_to_get_byte_at_0x6000[65245] .data:0045F6E3 point_passed_to_get_byte_at_0x6000 db 0FEDDh dup(?)
You see, IDA can only get two addresses: secret_array[] (start of the array) and point_passed_to_get_byte_at_0x6000.
How to deal with it: you can use hardware breakpoints on memory access operations (tracer has BPMx options) or symbolic execution engine or maybe you can write a plugin for IDA...
Surely, one array can be used for many values, not limited to boolean ones...
P.S. Optimizing MSVC 2015 is smart enough to optimize the get_byte_at_0x6000() function out.