/* Searches for |item| in |tree|. If found, initializes |trav| to the item found and returns the item as well. If there is no matching item, initializes |trav| to the null item and returns |NULL|. */ void * avl_t_find (struct avl_traverser *trav, struct avl_table *tree, void *item) { struct avl_node *p, *q; //assert (trav != NULL && tree != NULL && item != NULL); trav->avl_table = tree; trav->avl_height = 0; trav->avl_generation = tree->avl_generation; for (p = tree->avl_root; p != NULL; p = q) { int cmp = /*tree->avl_compare */CompareMemory (item, p->avl_data, tree->avl_param); if (cmp < 0) q = p->avl_link[0]; else if (cmp > 0) q = p->avl_link[1]; else /* |cmp == 0| */ { trav->avl_node = p; return p->avl_data; } //assert (trav->avl_height < AVL_MAX_HEIGHT); trav->avl_stack[trav->avl_height++] = p; } trav->avl_height = 0; trav->avl_node = NULL; return NULL; }
TEST(StringCompare, CompareMemory_Performance) { const char* volatile s1 = g_s1; const char* volatile s2 = g_s2; int total = 0; for (int i = 0; i < 1000000; ++i) { total += CompareMemory(s1, s2, sizeof(g_s1) - 1); } volatile int n = total; (void) n; }
/* Search |tree| for an item matching |item|, and return it if found. Otherwise return |NULL|. */ void * avl_find (const struct avl_table *tree, const void *item) { const struct avl_node *p; //assert (tree != NULL && item != NULL); for (p = tree->avl_root; p != NULL; ) { int cmp = /*tree->avl_compare */CompareMemory(item, p->avl_data, tree->avl_param); if (cmp < 0) p = p->avl_link[0]; else if (cmp > 0) p = p->avl_link[1]; else /* |cmp == 0| */ return p->avl_data; } return NULL; }
int ParseLine(unsigned long pid, char * lines, int start, int linesLen, int * skip, int doForceWrite) { if (pid == NULL || pid == 0) return start; char cType = lines[start]; int lineLen = 0, arg2Len = 0, arg1Off = 0, totalLenRead = 0, arg0 = 0; int arg0_2 = 0; for (lineLen = start; lineLen < linesLen; lineLen++) { if (lines[lineLen] == '\n' || lines[lineLen] == '\r') break; } lineLen -= start; int arg3Off = start + lineLen, arg4Off = arg3Off + 1, arg4Len = arg4Off; totalLenRead = lineLen; if (skip[0] <= 0) { skip[0] = 0; //Parse first line while (lines[(start + lineLen) - arg2Len] != ' ') arg2Len++; while (lines[start + arg1Off] != ' ') arg1Off++; char addrBuf[4]; memset(addrBuf, 0, 4); ReadHexPartial(lines, start + 1, (arg1Off - 1), addrBuf, (arg1Off - 1)/2); arg0 = (int)(((unsigned char)addrBuf[0] << 24) | ((unsigned char)addrBuf[1] << 16) | ((unsigned char)addrBuf[2] << 8) | ((unsigned char)addrBuf[3])); ReadHex(lines, start + arg1Off + 1, 8, addrBuf, 4); uint64_t addr = (uint64_t)(((unsigned char)addrBuf[0] << 24) | ((unsigned char)addrBuf[1] << 16) | ((unsigned char)addrBuf[2] << 8) | ((unsigned char)addrBuf[3])); if (ptrAddr != 0) { addr = ptrAddr; ptrAddr = 0; } char buf0[arg2Len/2]; char arg2Temp[arg2Len - 1]; if (arg0 < 0) arg0 = 0; char buf1[arg0]; //Check if theres a second line if ((start + lineLen + 1) < linesLen) { //Parse second line vars (for codes that need the second line //Get next code arguments while (arg3Off < linesLen && lines[arg3Off] != ' ') arg3Off++; arg4Off = arg3Off + 1; while (arg4Off < linesLen && lines[arg4Off] != ' ') arg4Off++; arg4Len = arg4Off + 1; while (arg4Len < linesLen && lines[arg4Len] != '\r' && lines[arg4Len] != '\n') arg4Len++; arg4Len -= arg4Off; } else arg4Len = 0; char buf0_2[arg4Len/2]; char buf1_2[(arg4Off - arg3Off)/2]; if (arg4Len == 0) goto skipSecondLine; //Get args for second line ReadHexPartial(lines, start + lineLen + 2, (arg3Off) - (start + lineLen + 2), addrBuf, ((arg3Off) - (start + lineLen + 2))/2); arg0_2 = (uint)(((unsigned char)addrBuf[0] << 24) | ((unsigned char)addrBuf[1] << 16) | ((unsigned char)addrBuf[2] << 8) | ((unsigned char)addrBuf[3])); //Get address for second line ReadHexPartial(lines, arg3Off + 1, arg4Off - arg3Off - 1, buf0_2, (arg4Off - arg3Off - 1)/2); //Get value for second line ReadHexPartial(lines, arg4Off + 1, arg4Len - 1, buf1_2, (arg4Len - 1)/2); skipSecondLine: ; switch (cType) { case '0': ; //Write bytes (1=OR,2=AND,3=XOR,rest=write) switch (arg0) { case 1: //OR ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); //Get source bytes get_process_mem(pid, addr, buf1, (arg2Len/2), isDEX, isCCAPI); //Or each byte for (uint cnt0 = 0; cnt0 < (uint)(arg2Len/2); cnt0++) buf1[cnt0] |= buf0[cnt0]; //Write bytes to dest WriteMem(pid, addr, buf1, (arg2Len/2)); break; case 2: //AND ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); //Get source bytes get_process_mem(pid, addr, buf1, (arg2Len/2), isDEX, isCCAPI); //And each byte for (uint cnt0 = 0; cnt0 < (uint)(arg2Len/2); cnt0++) buf1[cnt0] &= buf0[cnt0]; //Write bytes to dest WriteMem(pid, addr, buf1, (arg2Len/2)); break; case 3: //XOR ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); //Get source bytes get_process_mem(pid, addr, buf1, (arg2Len/2), isDEX, isCCAPI); //Xor each byte for (uint cnt0 = 0; cnt0 < (uint)(arg2Len/2); cnt0++) buf1[cnt0] ^= buf0[cnt0]; //Write bytes to dest WriteMem(pid, addr, buf1, (arg2Len/2)); break; default: ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); WriteMem(pid, addr, buf0, (arg2Len/2)); break; } break; case '1': //Write text //Get total text write size arg1Off++; while (lines[start + arg1Off] != ' ') arg1Off++; arg2Len = lineLen - arg1Off; strncpy(buf0, lines + (start + lineLen) - arg2Len + 1, arg2Len - 1); buf0[arg2Len-1] = '\0'; WriteMem(pid, addr, buf0, arg2Len - 1); break; case '2': //Write float strncpy(buf0, lines + (start + lineLen) - arg2Len + 1, arg2Len - 1); float buf2Flt = (float)___atof(buf0); //atof(buf2); WriteMem(pid, addr, (char*)&buf2Flt, arg2Len - 1); totalLenRead = lineLen; break; case '4': ; //Write condensed //Get count uint count = (uint)(((unsigned char)buf1_2[0] << 24) | ((unsigned char)buf1_2[1] << 16) | ((unsigned char)buf1_2[2] << 8) | ((unsigned char)buf1_2[3])); //Get increment uint64_t inc = (uint64_t)(((unsigned char)buf0_2[0] << 24) | ((unsigned char)buf0_2[1] << 16) | ((unsigned char)buf0_2[2] << 8) | ((unsigned char)buf0_2[3])); //Get write ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, arg2Len / 2); for (uint cnt4 = 0; cnt4 < count; cnt4++) { WriteMem(pid, addr + (uint64_t)(cnt4 * inc), buf0, (arg2Len/2)); if (arg0_2 != 0) *(uint*)buf0 += (arg0_2 << (((arg2Len/2) % 4) * 8)); } skip[0]++; break; case '6': //Write pointer //Get offset ReadHexPartial(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, (arg2Len - 1)/2); uint64_t offset = (uint64_t)(((unsigned char)buf0[0] << 24) | ((unsigned char)buf0[1] << 16) | ((unsigned char)buf0[2] << 8) | ((unsigned char)buf0[3])); //Get address at pointer get_process_mem(pid, addr, buf0, 4, isDEX, isCCAPI); ptrAddr = (uint64_t)(((unsigned char)buf0[0] << 24) | ((unsigned char)buf0[1] << 16) | ((unsigned char)buf0[2] << 8) | ((unsigned char)buf0[3])); ptrAddr += offset; break; case 'A': //Copy paste switch (arg0) { case 1: //if (typeA_Copy) // _free(typeA_Copy); //Get count ReadHexPartial(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, (arg2Len - 1)/2); uint count = (uint)(((unsigned char)buf0[0] << 24) | ((unsigned char)buf0[1] << 16) | ((unsigned char)buf0[2] << 8) | ((unsigned char)buf0[3])); typeA_Size = count; //typeA_Copy = (char *)_malloc(count); typeA_Copy = (char *)mem_alloc(0); get_process_mem(pid, addr, typeA_Copy, 4, isDEX, isCCAPI); memcpy(arg2Temp, lines + ((start + lineLen) - arg2Len + 1), arg2Len - 1); break; case 2: if (!typeA_Copy || typeA_Size <= 0) break; WriteMem(pid, addr, typeA_Copy, typeA_Size); break; } break; case 'B': //Find Replace //Only work when doForceWrite is true (1) which means everytime the user activates Artemis from the in game XMB //Don't want to waste time constantly searching if (!doForceWrite) break; //Get end addr ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, addrBuf, 4); uint64_t endAddr = (uint64_t)(((unsigned char)addrBuf[0] << 24) | ((unsigned char)addrBuf[1] << 16) | ((unsigned char)addrBuf[2] << 8) | ((unsigned char)addrBuf[3])); //new (COP) length uint binc = arg4Len/2; //original (OGP) length uint cmpSize = (arg4Off - arg3Off)/2; //Flip addresses uint64_t temp = 0; if (endAddr < addr) { temp = addr; addr = endAddr; endAddr = temp; } for (uint64_t curAddr = addr; curAddr < endAddr; curAddr += (scanInc - cmpSize)) { if (get_process_mem(pid, curAddr, (char *)memBuf, scanInc, isDEX, isCCAPI) >= 0) { //So we stop it each loop before (scanInc - cmpSize) in the instance that //the result is the last 2 bytes, for instance, and the compare is actually 4 bytes (so it won't result even though it should) //This fixes that for (uint64_t boff = 0; boff < (scanInc - cmpSize); boff++) { //Break if count reached if (arg0 > 0 && temp >= (uint64_t)arg0) break; if ((curAddr + boff) >= endAddr) break; if (CompareMemoryBuffered((char *)memBuf, boff, buf0_2, cmpSize)) { //printf ("Instance found at 0x%08x, writing 0x%x (%d)\n", curAddr + boff, *(uint*)buf1_2, binc); WriteMem(pid, curAddr + boff, buf1_2, binc); //Just skip in case the replacement has, within itself, the ogp //We subtract one because it gets added back at the top of the loop boff += binc - 1; temp++; } } } } skip[0]++; totalLenRead = lineLen; break; case 'D': //Write conditional ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); int DisCond = CompareMemory(pid, addr, buf0, arg2Len / 2); if (!DisCond) { skip[0] += arg0; } break; case 'E': //Write conditional (bitwise) ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); int EisCond = CompareMemoryAnd(pid, addr, buf0, arg2Len / 2); if (!EisCond) { skip[0] += arg0; } break; case 'F': //Copy bytes //Get destination ReadHex(lines, (start + lineLen) - arg2Len + 1, arg2Len - 1, buf0, 4); uint64_t dest = (uint64_t)(((unsigned char)buf0[0] << 24) | ((unsigned char)buf0[1] << 16) | ((unsigned char)buf0[2] << 8) | ((unsigned char)buf0[3])); //Get source bytes get_process_mem(pid, addr, buf1, arg0, isDEX, isCCAPI); //Write bytes to dest WriteMem(pid, dest, buf1, arg0); break; } } else skip[0]--; return start + totalLenRead; }
/* Deletes from |tree| and returns an item matching |item|. Returns a null pointer if no matching item found. */ void * avl_delete (struct avl_table *tree, const void *item) { /* Stack of nodes. */ struct avl_node *pa[AVL_MAX_HEIGHT]; /* Nodes. */ unsigned char da[AVL_MAX_HEIGHT]; /* |avl_link[]| indexes. */ int k; /* Stack pointer. */ struct avl_node *p; /* Traverses tree to find node to delete. */ int cmp; /* Result of comparison between |item| and |p|. */ //assert (tree != NULL && item != NULL); k = 0; p = (struct avl_node *) &tree->avl_root; for (cmp = -1; cmp != 0; cmp = /*tree->avl_compare */CompareMemory (item, p->avl_data, tree->avl_param)) { int dir = cmp > 0; pa[k] = p; da[k++] = (unsigned char)dir; p = p->avl_link[dir]; if (p == NULL) return NULL; } item = p->avl_data; if (p->avl_link[1] == NULL) pa[k - 1]->avl_link[da[k - 1]] = p->avl_link[0]; else { struct avl_node *r = p->avl_link[1]; if (r->avl_link[0] == NULL) { r->avl_link[0] = p->avl_link[0]; r->avl_balance = p->avl_balance; pa[k - 1]->avl_link[da[k - 1]] = r; da[k] = 1; pa[k++] = r; } else { struct avl_node *s; int j = k++; for (;;) { da[k] = 0; pa[k++] = r; s = r->avl_link[0]; if (s->avl_link[0] == NULL) break; r = s; } s->avl_link[0] = p->avl_link[0]; r->avl_link[0] = s->avl_link[1]; s->avl_link[1] = p->avl_link[1]; s->avl_balance = p->avl_balance; pa[j - 1]->avl_link[da[j - 1]] = s; da[j] = 1; pa[j] = s; } } //tree->avl_alloc->libavl_free (/*tree->avl_alloc,*/ p); SMFree(p); //assert (k > 0); while (--k > 0) { struct avl_node *y = pa[k]; if (da[k] == 0) { y->avl_balance++; if (y->avl_balance == +1) break; else if (y->avl_balance == +2) { struct avl_node *x = y->avl_link[1]; if (x->avl_balance == -1) { struct avl_node *w; //assert (x->avl_balance == -1); w = x->avl_link[0]; x->avl_link[0] = w->avl_link[1]; w->avl_link[1] = x; y->avl_link[1] = w->avl_link[0]; w->avl_link[0] = y; if (w->avl_balance == +1) x->avl_balance = 0, y->avl_balance = -1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == -1| */ x->avl_balance = +1, y->avl_balance = 0; w->avl_balance = 0; pa[k - 1]->avl_link[da[k - 1]] = w; } else { y->avl_link[1] = x->avl_link[0]; x->avl_link[0] = y; pa[k - 1]->avl_link[da[k - 1]] = x; if (x->avl_balance == 0) { x->avl_balance = -1; y->avl_balance = +1; break; } else x->avl_balance = y->avl_balance = 0; } } } else { y->avl_balance--; if (y->avl_balance == -1) break; else if (y->avl_balance == -2) { struct avl_node *x = y->avl_link[0]; if (x->avl_balance == +1) { struct avl_node *w; //assert (x->avl_balance == +1); w = x->avl_link[1]; x->avl_link[1] = w->avl_link[0]; w->avl_link[0] = x; y->avl_link[0] = w->avl_link[1]; w->avl_link[1] = y; if (w->avl_balance == -1) x->avl_balance = 0, y->avl_balance = +1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == +1| */ x->avl_balance = -1, y->avl_balance = 0; w->avl_balance = 0; pa[k - 1]->avl_link[da[k - 1]] = w; } else { y->avl_link[0] = x->avl_link[1]; x->avl_link[1] = y; pa[k - 1]->avl_link[da[k - 1]] = x; if (x->avl_balance == 0) { x->avl_balance = +1; y->avl_balance = -1; break; } else x->avl_balance = y->avl_balance = 0; } } } } tree->avl_count--; tree->avl_generation++; return (void *) item; }