Показаны сообщения с ярлыком C. Показать все сообщения
Показаны сообщения с ярлыком C. Показать все сообщения

2010-06-16

Шифрование строк

Иногда необходимо зашифровать строки в программе, это хоть немного, но затрудняет реверсинг. Недавно и мне потребовалось решить эту задачу. Решено было написать некоторый аналог препроцессора на python-е. Препроцессор просто заменяет макрос _C на вызов функции CSDecrypt. Например, этот код:

#include <stdio.h>
#include <windows.h>
#include "_CSD.h"

int f(char * t) {
  printf(_C("|t:%s| "),t);
  return 0;
}

int main(int argc, char ** argv) {
  f(_C("testing"));
  f(_C("test2"));
  return 1;
}


будет преобразован в следующий:

#include <stdio.h>
#include <windows.h>
#include "_CSD.h"

int f(char * t) {
  printf(CSDecrypt("\x00\xf2\xfb\xaa\xb4\xe1\xef\xb4",7,142),t);
  return 0;
}

int main(int argc, char ** argv) {
  f(CSDecrypt("\x00\xe7\xf1\xe6\xe2\xfe\xf6\xfe",7,147));
  f(CSDecrypt("\x00\x14\x04\x11\x17\x56",5,96));
  return 1;
}


_CSD.h содержит функцию расшифровки.

#pragma once

inline char* CSDecrypt(char *str, size_t len, BYTE key) {
  char *flag = str;
  str++;
  if (*flag=='\x01') {
    return str;
  }
  for (int i=0;i<len;i++) {
    str[i]^=(key+i);
  }
  *flag = '\x01';
  return str;
}



Желательно передать компилятору /Ob1, т.к. inline. И ещё, важный момент, память, в которай расположенна строка, должна быть доступна для записи, иначе будет исключение C0000005 (ACCESS VIOLATION).

вот сам код "препроцессора":

import sys, re
from random import randint

def XorStr(str,key):
  retval = ""
  for i in range(0,len(str)):
    t = ord(str[i])^int(key+i)
    retval += chr(t)
  return retval

def FmtXorStr(str):
  retval = r"\x00"
  for x in str:
    retval += r"\x%02x" % ord(x)
  return retval

def _C(obj):
  key = randint(1,254)
  str = XorStr(obj.group(1),key)
  retval = 'CSDecrypt("%s",%d,%d)' % (FmtXorStr(str),len(obj.group(1)),key)
  return retval

def main():
  try:
    f = open(sys.argv[1],"r")
    code = f.read()
    f.close()
    dest = open(sys.argv[2],"w")
  except:
    print "%s <in> <out>" % sys.argv[0]
    return 0
  
  r = re.sub(r'_C\("(.*?)"\)',_C,code)
  dest.write(r)
  dest.close()
  return 1

main()



Я сейчас почти полностью перешел на vim + scons. Вот пример как подключить "препроцессор" (pre.py) к scons:

env = Environment(
  CCFLAGS = "/Ob1 /c /D_CSD",
  LINKFLAGS = "/MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR"
)

PyPre = Builder(action = 'pre.py $SOURCE $TARGET',
    src_suffix = '.cpp', suffix = '.cxx')

env["BUILDERS"]["PyPre"] = PyPre

for x in Glob("*.cpp"):
  env.PyPre(x)

env.Program("test.exe",Glob("*.cxx"))


Конечно могут быть всякие баги-глюки, т.к. не особо тестилось всё это. Но осоновная идея я думаю понятна. Из известных недостатков:

1. Нельзя юзать так: char a[] = _C("test");
2. Не корректно обрабатываются спецсимволы ( например \n\r )
3. ...

UPD
проблема со спецсимволами решается через .decode("string_escape")

2010-01-11

Hook api

Небольшой код для перехвата функций методом модификации импорта.

bool HookImport(DWORD Base, DWORD Org, DWORD Hook)
{
    PIMAGE_FILE_HEADER pFileHdr;
    PIMAGE_OPTIONAL_HEADER pOptHdr;
    PIMAGE_IMPORT_DESCRIPTOR pImpDesc;
    bool rv = false;

    pFileHdr = (PIMAGE_FILE_HEADER)(*(PDWORD)(Base+0x3c)+Base+4);
    pOptHdr = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHdr+sizeof(IMAGE_FILE_HEADER));
    pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(Base +
                pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    for ( int i=0;pImpDesc[i].Characteristics; i++ )
    {
        char * CurrentModuleName = (char*)(pImpDesc[i].Name + Base);
        PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(pImpDesc[i].FirstThunk + Base);
        for ( int j=0; pThunk[j].u1.Ordinal; j++ )
        {
            if (pThunk[j].u1.Function == Org)
            {
                pThunk[j].u1.Function = Hook;
                rv = true;
                goto Exit;
            }
        }
    }
    Exit:
    return rv;
}

2010-01-04

Двусвязные списки

Когда-то написал этот простой набор макросов, и юзаю практически везде где требуются двусвязные списки:

#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED

#define INIT_LIST_HEAD(head) \
  (head)->Flink = (head); \
  (head)->Blink = (head)

#define UNLINK_ENTRY(entry) \
  (entry)->Blink->Flink = (entry)->Flink; \
  (entry)->Flink->Blink = (entry)->Blink

#define ADD_ENTRY(head,entry) \
  (entry)->Flink=(head)->Flink; \
  (entry)->Blink=(head); \
  (head)->Flink->Blink = (entry); \
  (head)->Flink = (entry)

#define ADD_ENTRY_TAIL(head,entry) \
  (head)->Blink->Flink = (entry); \
  (entry)->Blink = (head)->Blink; \
  (entry)->Flink = (head); \
  (head)->Blink = (entry)

#define get_list_entry(type,entry)  (type)(entry)

#define list_for_each(pos, head) \
  for (pos = (head)->Flink; pos!=(head); pos = (pos)->Flink)

#define list_for_each_safe(pos, n, head) \
  for (pos = (head)->Flink, n = pos->Flink; pos != (head);\
    pos = n, n = (pos)->Flink)

#endif // LIST_H_INCLUDED

2009-05-10

hki - кейлогер

Отладил наконец-то свой кейлогер. Работает через перехват IRP. В лог-файл (по умолчанию C:\124.txt) пишет коды клавиш, и заголовок активного окна. Тестировался на Windows Vista SP1 и Windows XP Sp2 на двухядерном прцессоре. В комплекте простой парсер лог-файлов, парсер написан на коленке и скорей всего будет передалан, но как-нибудь в другой раз. При написании парсера использовалась часть кода из r0keylog barton'а.

Конечно код далёк от совершенства, но тем-не менее, вот сcылка для скачивания:
http://cid-eea2a7c767291ff9.skydrive.live.com/self.aspx/.Public/hki.rar

2009-05-02

Пример кода epoll

Очень базовый пример обработки входящих соединений с epoll:

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <strings.h>

#define EPOLL_RUN_TIMEOUT 1000
#define MAXEVENTS 50

int got_connect(fd) {
printf("got data\n");
return 0;
}

int main(int argc, char *argv[]){
if(argc<2){
printf("Usage: %s <port>\n",argv[0]);
return -1;
}

int port=atoi(argv[1]);
int epfd = epoll_create(512);
int nfds, cs, i;

struct epoll_event ev, *events;
struct sockaddr_in serv, cli;
int connected_fd;
int listenfd=socket(AF_INET, SOCK_STREAM, 0);

bzero(&serv,sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = htonl(INADDR_ANY);
serv.sin_port = htons(port);

bind(listenfd,(struct sockaddr*)&serv,sizeof(serv));
listen(listenfd, 50);

ev.events = EPOLLIN | EPOLLET | EPOLLHUP;
ev.data.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
int addrlen = sizeof(cli);

while(1){
nfds = epoll_wait(epfd,events,MAXEVENTS,EPOLL_RUN_TIMEOUT);
if(nfds<0){
printf("epoll_wait error\n");
return -1;
}
for (i=0;i<nfds;++i){
if(events[i].data.fd == listenfd){
connected_fd = accept(listenfd, (struct sockaddr *) &cli,&addrlen);
printf("addr: %s\n",inet_ntoa(cli.sin_addr.s_addr));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connected_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, connected_fd, &ev);
}
else{
got_connect(events[i].data.fd);
}
}
}
close(epfd);
return 0;
}

Сцылки по теме:
http://www.kegel.com/c10k.html

http://www.monkey.org/~provos/libevent/
http://www.xmailserver.org/linux-patches/nio-improve.html

2008-12-20

Загрузка драйверов в Windows

Один из самых простых способов загрузить драйвер в Windows - использльзовать SCM (Service Control Manager). Для быстрой загрузки/выгрузки своих небольших драйверов, я набросал програмку. Програма создаёт службу(Service) типа SERVICE_KERNEL_DRIVER с именем test_driver (соответственно в реестре создаёться раздел HKLM/System/CurrentControlSet/Services/test_driver). Подробнее про cлужбы можно почитать на wasm.ru

//Service Control Programm
#include <windows.h>
#include <stdio.h>
#define MAX_L 256

char *sn="test_driver";
char *dn="test_driver";

int unload()
{
SC_HANDLE hSCM, hService;
SERVICE_STATUS status;

hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if(hSCM == NULL){
printf("[!] Error in OpenSCManager\n");
return -1;
}
hService = OpenService(hSCM, sn , SC_MANAGER_ALL_ACCESS);

if(!hService){
printf("Error in hService\n");
return -1;
}
if(ControlService(hService, SERVICE_CONTROL_STOP, &status) != TRUE){
printf ("[!] Error in ControlService. Code: %.x\n",GetLastError());
return -1;
}
DeleteService(hService);
printf("stoped..\nUnloaded..\n");
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return 1;
}

int load(char * path)
{
SC_HANDLE hSCM, hService;
hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if(hSCM == NULL){
printf("[!] Error in OpenSCManager\n");
return -1;
}

GetFullPathName(path,MAX_L,path,NULL);

hService = CreateService(hSCM, sn, dn, SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, path,
NULL, NULL, NULL, NULL, NULL);

if(StartService(hService,0,NULL)!=TRUE){
printf("[!] Error in StartService. Code: %.x\n",GetLastError());
return -1;
}
printf("Now driver loaded in kernel memory.\n");
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return 1;
}

void usage(char * p){
printf("Load driver: %s l \nUnload driver: %s u",p,p);
exit(0);
}

int main(int argc, char * argv[])
{
int r = 0;
if(argc<2) usage(argv[0]);
switch(*argv[1])
{
case 'l':
if(argc!=3) usage(argv[0]);
r = load(argv[2]);
case 'u':
if(argc<2) usage(argv[0]);
r = unload();
default:
usage(argv[0]);
}
return r;
}

2008-12-12

SDT

Осваиваюсь с внутреним устройством Windows, вот, набросал кодес для получения данных из SDT. Например получим номер функции NtCreateProcessEx которая в Windows Vista SP1 находиться по адрессу 0x826a8fea, а в Windows XP SP2 - 0x805c5c32:

#include <ntddk.h>

extern PUSHORT NtBuildNumber;
extern PVOID KeServiceDescriptorTable;

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegPath)
{
unsigned long t, t2, p, pNtCreateProcessEx;
int i,j;

switch(*NtBuildNumber){
case 2600: //winxp
pNtCreateProcessEx = 0x805c5c32;
break;

case 6001: //vista (at least sp1)
pNtCreateProcessEx = 0x826a8fea;
break;
}

DbgPrint("[+] Driver successfuly loaded\n");
DbgPrint("SDT addr: %x\n", KeServiceDescriptorTable);

t = *((PULONG)KeServiceDescriptorTable);
for (i=j=0;j<=391;i+=4,j++){
t2 = *((PULONG)(t+i));
if(t2 == pNtCreateProcessEx){
DbgPrint("NtCreateProcess index: %d addr:%x\n", j,t2);
}
}
return STATUS_DEVICE_CONFIGURATION_ERROR;
}

2008-08-19

Змейка на Си

Змейка на ncurses =) Для компиляции нужна библиотека ncursess, скорей всего есть по-умолчанию: gcc -lcurses snake.c -o snake
Есть глюк, если во время движения, поверуть в противоположную сторону - змейка сама в себя врежеться. Например, если при движении вверх, нажать вниз - то врежеться змейка в себя. Надо бы как-нибудь поправть. Кстати, мой рекорд - 64 =)

#include <curses.h>
#include <stdlib.h>

#define WH 25
#define WW 25

#define MAX_SNAKE 255

typedef struct{
int y;
int x;
} head_struct;

typedef struct snk_St{
int y;
int x;
struct snk_St *next;
} snk_s;

snk_s *snk;
head_struct set_food(){
head_struct food;
food.y=1+(int)(23.0 * (rand()/(RAND_MAX+1.0)));
food.x=1+(int)(23.0 * (rand()/(RAND_MAX+1.0)));
return food;
}

int main(){
head_struct body[MAX_SNAKE], food;
int lose=0;
char *space=" ";
WINDOW *my_win, *stats_win, *lose_win;
char *str="GAME OVER press F1 to quit";
initscr();
nonl();
noecho();
timeout(60);
curs_set(0);
start_color();
if(has_colors()){
init_pair(1,COLOR_GREEN,COLOR_BLACK);
init_pair(2,COLOR_CYAN,COLOR_BLACK);
}
stats_win=newwin(3,WW+10,1,2);
wbkgd(stats_win,COLOR_PAIR(1));

my_win=newwin(WH,WW,4,7);
wbkgd(my_win,COLOR_PAIR(1)|A_BOLD);

lose_win=newwin(3,(strlen(str)+4),14,4);
wbkgd(lose_win,COLOR_PAIR(2)|A_BOLD|A_BLINK);
box(lose_win,0,0);
body[0].y=2;
body[0].x=2;
box(my_win,0,0);
int old_c=66,c,food_c=0,score=1,b=0;
for(;;)
{
if(!food_c){
food=set_food();
food_c=1;
}


if (body[0].x==food.x && body[0].y==food.y){
score+=1;
if(score == 254) lose=1;
food_c=0;
}

c=getch();
if (old_c==65 && c==66) c=65;
if (old_c==66 && c==65) c=66;
if (old_c==67 && c==68) c=67;
if (old_c==68 && c==67) c=67;
(c==ERR)?(c=old_c):(old_c=c);
for(b=score+1;b!=0;b--){
body[b].y=body[b-1].y;
body[b].x=body[b-1].x;
}


switch(c){
case 65:
body[0].y-=1;
if(body[0].y==0) body[0].y=23;
break;

case 66:
body[0].y+=1;
if(body[0].y==24) body[0].y=1;
break;
case 67:
body[0].x+=1;
if(body[0].x==24) body[0].x=1;
break;
case 68:
body[0].x-=1;
if(body[0].x==0) body[0].x=23;
break;
}
for(b=score-1;b>3;b--){
if(body[0].y==body[b].y && body[0].x==body[b].x){
lose=1;
}

}
if(lose==1){
break;
}
mvwaddch(my_win,food.y,food.x,'F');
mvwaddch(my_win,body[0].y,body[0].x,'@');
mvwaddch(my_win,body[1].y,body[1].x,'*');
mvwaddstr(my_win,body[score].y,body[score].x,space);

mvwprintw(stats_win,1,1,"Score: %d; Food: Y=%.02d X=%.02d",score,food.y,food.x);
wnoutrefresh(stats_win);
mvwaddch(my_win,body[score].y,body[score].x,32);
wnoutrefresh(stats_win);

wnoutrefresh(my_win);
doupdate();
}
wclear(my_win);
wclear(stats_win);

mvwaddstr(lose_win,1,2,str);
wnoutrefresh(lose_win);
doupdate();
c=0;
for(;;){
c=getch();
if(c==80) break;
c=0;
}
endwin();
return 0;
}

Архив