그냥 별 건 없고 레트로에 꽂혔는데 적당한 테마가 없어서 윈98 컨셉으로 작업.

아이콘을 제외하고 최대한 이미지를 배제하였음. 대부분 CSS로 처리했다.

status bar에 있는 냥캣은 그냥 기믹. 누르면 랜덤으로 음악이 재생된다.

 


제목은 쓸데없는 검색 유입을 막기 위해서,, 써방을 해 두었음

원래 목적은 익스프레스엔진용 모듈 중에 추가하면 재밌을 만한 거 없나..하다가 그냥 직접 만들어 볼까 싶기도 했고 의뢰받은 것도 있고 해서 연습 삼아 시작한 것. 포인트 복*도 몇 만 원 받던데 이거도 팔면 ..음 누가 사가긴 하려나...

php, html, javascript전부 다 잘 모르는 분야이기 때문에 그냥 야매로 만들었다ㅋㅋ jsp로 게시판 만들어본 게 웹에 대한 마지막 기억이고 ㅋㅋㅋㅋ 심지어 자바스크립트에서 클래스 선언도 어떻게 하는지 모르겠어서 레퍼런스 찾아보면서 시작했다ㅋㅋㅋㅋㅋ 만들어 놓고도 저게 맞는 건지 모르겠음ㅋㅋㅋㅋㅋ 카드 이쁘게 좌라락 뜨는 것도 어떻게 하면 좋을지 몰라서 이또한 야매로.. setTimeout과 setInterval로 아무렇게나 했고,, 솔직히 jquery slideDown이 너무 적절하게 잘 어울릴 것 같아서 이래저래 노력해봤는데 동작이 안 되어서,, 슬펐다.. jquery어떻게 쓰는지도 모르겠음..

하튼 그래도 이틀 정도 짬내니 금방 만든 것 같다..지만 솔직히 게임만 구현해둔 프로토타입이라 php와 db어쩌구저쩌구연동도 하려면 갈 길은 멀듯..

그냥, 오랜만에 뭔가 사소한 거라도 코딩을 해보니까 즐거웠다. 정말 많은 생각이 들 정도로..


카드 이미지는 OpenGameArt에서 프리 소스를 이용하였고, 나머지는 직접.



+. 급하게 모듈 연동 시키느라 다른 소스 막 갖다붙여서 쓰고 그랬네.. 공식적으로는 못쓰는 모듈이 될 것 같지만 개인용도로 의뢰받았으니..괜찮겠지

디자인 맡아주신 분 덕분에 지금은 스샷과 많이 달라졌고..ㅋㅋ 훨씬 예뻐졌다 :)

걍 내 컴에서 돌아가게 만들어서 호환안될수도있음

귀ㅣ차나서 웅........

랜선 꽂혀있는 상태에서 연결 끊어버리는 프로그램

직접랜선뽑고꼽고하기귀찮아서만듦 태블릿으론 명령어 치기 불편해서 자동으로 쳐주는 것임 끗


zzowitch.exe


미친 다음새기들 사진업로더를 플래시로만들면어떡해...............ㅡㅡ; 점점 퇴보하고있다...플래시없앨거라며..

기존에 급조했던 매크로(http://zzoyu.tistory.com/105 이것도 공개X)가 생각보다 성능이 좋았다.

친구말로는 스탠딩석만 서른 다섯번 잡아봤다고(...)

내가 만들었지만 내 프로그램을 안믿는지라 별 기대는 안했다만 정말 예상외로 그냥 평범하게 '쓸만하다'.

그 때 부터 지금까지 많은 일이 있었고(내가 처음으로 아이돌에 입덕했다거나...미나야언니가가난해서미안해.....) 그래서 기왕 이렇게 된 거 좀 수정해보기로 했다.

나름 이런저런 특이한 시도를 많이 해봤기때문에 일단 사진을 모자이크하기로 한다(........어느정도 추정 가능한게 함정............)

지금은 저 사진에 비해 굉장히 길어졌다.... 구역건너뛰는 일명 이삭줍기도 넣었고 그외기타등등...............

기능 추가는 대부분 끝났고, 최적화나 자잘한 버그를 해결할 예정.

그리고 거의 취케팅 전용 프로그램이었는데, 티케팅도 가능하게 시도해보려한다.흐흐 <-가능하게 했는데 사이트 리뉴얼로 수정필요,,ㅅi파,,,,,,,,,,

오랜만에 프로그램 짜니까 참 즐겁다.

오탘쿠 친구의 부탁으로 급조. 원하는 좌석이 나올 때 까지 새로고침하며 확인하고, 제일 앞줄의 좌석을 선택하고 결제창까지 넘어가는 단순반복 매크로.

아마 거의 모든 사이트, 모든 좌석에 다 대응할 수 있도록 만듦(Y모사이트와 I모사이트만 확인했지만).

대신 사전 준비가 좀 번거롭다. 그래도 최대한 사용하기 편하게 만들려고 노력함.

위치값을 일일이 쳐서 넣는건 불편할 것 같아서 버튼 클릭 후 해당 위치를 클릭하도록 만들었다던지...

파일 공유는 하지 않을 생각..


VS2010, MFC. 약 이틀.

전역후킹, 스크린캡쳐, SendInput 위주로 이용.


 

 간단한 타이머가 필요하여 MFC로 만들어본 프로그램입니다. 시간의 경과를 확인할 수 있고 임의로 멈추는 기능이 있습니다. 또한 항상 위에 창을 고정시켜 다른 창에 가려지지 않도록 할 수 있고, 투명도를 조절하는 것도 가능합니다.

기본적인 부분만 구현했고 그 외의 기능 추가를 고려중입니다.

 

StudyTimer.exe

(간혹 브라우저가 다운로드나 실행을 막아버리는데 결코 유해한 프로그램이 아닙니다. 디지털 인증 등록어떻게 하는거야ㅠㅠ)

 

 

실행이 안된다면 http://www.microsoft.com/ko-kr/download/details.aspx?id=5555 에서 재배포 패키지를 설치하시기 바랍니다.


시험공부하다가 진짜 잉여로운 발상에 만든 프로그램. 출첵 이벤트 계속 참여하기가 귀찮아서 만들었다

어떤 함수 썼는지는 뻔하고 입력 위치는 거의 하드코딩으로 했음. 스샷 보다시피 MFC로 만듦.

좀 더 유연하게 만들려고 하면 할 수는 있는데 귀찮아서 여기까지만 함.

잘하면 낚시 매크로도 만들 수 있지 않을까 함. 이건 좀 더 나중에 시간이 나면 해볼 예정...

나 모험가 달인작 끝내기 전에는 가능하기나 할까 모르겠다



프로그램 자체는 이런 느낌. 아이디 비번 접속시간 적고 고고싱 누르면 클라이언트 켜고, 게임시작 누르고,

호환성체크 넘어가고 로그인하고 캐릭터 선택해서 들어가서 지정한 시간만큼 대기 후 자동으로 꺼지도록 함.

악용하면 충분히 악용할 수 있고, 블로그에 올려도 어차피 모르는 사람이 만든 프로그램을

꺼리낌없이 막 쓸 배짱 있는 사람도 없을 것이기 때문에 공개는 하지 않겠음.



그럼 뿅

개요

 글자수를 세는 프로그램을 만들기 위해 제작. 너무 간단한 구조라 설명이 딱히 필요할 것 같지는 않다. 앞으로의 목표는 일반 텍스트 에디터에서 글을 선택한 상태에 특정 키를 누르면 툴팁 등으로 몇자인지 알려주는 것이나 현재는 구상만 해둔 상태


개발 언어 : C+Win32API

개발 기간 : 하루



실행 사진

<입력을 대기중>


<글자가 입력되었을 때 상태바에 글자 수를 표시>



실행 파일


CharacterCounter.exe


1. 개요

 응용 프로그램의 PE 헤더를 분석하고, 코드 영역과 데이터 영역을 가상 머신 내에 적재하여 프로그램을 가상으로 실행하는 프로그램이다. 함수가 실행되고 되돌아가는 원리와 컨텍스트 스위칭 기법을 이용한 것으로, 실행 전 메모리 상태와 실행 후 메모리 상태, 현재 레지스터 상태를 볼 수 있도록 되어있다.


사용 언어 : C / ASM



2. main.c

2-1. 프로그램 흐름

1. 준비

1. 커맨드를 받기 전에 미리 컨텍스트를 저장해 놓는다.

- 저장하는 시점이 가상 프로그램 실행 전이 되서는 안된다(무한루프의 가능성)

2. 커맨드 받기를 기다린다.

2. 프로그램 로드(커맨드가 LOAD일 경우)

1. 파일 체크

- 유효한 파일인가?

- 실행 파일인가?(매직 넘버가 'MZ'인지 체크)

2. 헤더를 분석해 헤더의 전체 크기를 구하고, 이를 이용해 코드 영역과 데이터 영역의 시작위치를 찾음

3. 찾아낸 시작위치만큼 lseek를 이용해 건너뛴 뒤, 미리 만들어 둔 코드/데이터 영역에 적재

3. 실행

1. 새로운 컨텍스트 구조체를 만듬

- eax에 이전에 미리 만들어 둔 구조체의 주소를 넣는다

-> 이후 실행 될 프로그램이 마지막에 호출할 함수의 인자가 된다

- eip에 적재해 둔 코드 영역의 시작 주소를 넣는다

-> 코드 영역으로 점프하여 수행하게 된다

- esp에 stack 영역의 마지막+4를 가르키도록 한다

-> push는 한 칸 움직인 후 값을 넣는다

-> 스택은 끝에서 부터 +4씩 이동한다

2. 새로운 컨텍스트로 스위칭

- 프로그램이 실행되며, 이 때 제일 먼저 eax를 push하게 되어 있어야 한다

3. 등록해 둔 실행파일의 마지막 함수(LDST)를 수행

- push된 eax의 값으로 컨텍스트 스위칭을 시도

4. 커맨드를 받기 전의 시점(1-1)로 점프하여 되돌아온다


2-2. 소스

(들여쓰기가 원본 소스에 비해 조금 이상하게 되어 있습니다)

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <windows.h>

#include <winnt.h>


#define MAX_PROGRAM_SIZE 0x10000 // 64KB

#define SECTION_SIZE 512


#define MEMORY_START 0

#define MEMORY_END 1

#define CODE 2

#define DATA 3

#define STACK 4


typedef struct _command

{

const unsigned char *ucpCommand;

const unsigned char *ucpDetail;

void( *fp )();

} COMMAND;


typedef struct _CONTEXT_INFO

{

int efl;

int eip;

int edi;

int esi;

int ebp;

int esp;

int ebx;

int edx;

int ecx;

int eax;

} CONTEXT_INFO;


void ChaseAddress( unsigned char * _uCp, int _iSize );

void DrawHeader();


void STST( CONTEXT_INFO *stpReg ); // CPU의 정보를 메모리에 저장

void LDST( CONTEXT_INFO *stpReg ); // 메모리에 저장된 CPU 정보를 재등록


unsigned char MD( int * ); // Memory Display Function By Assembly

void MM( int *, char); // Memory Modify Function By Assembly


void PrintRegister( CONTEXT_INFO *stpReg );


void Command();


void ViewCode();

void ViewData();

void ViewStack();

void OpenExcutable();

void Exit();

void ViewRegister();

void MemoryClear();

void Go();


unsigned char ucMemory[MAX_PROGRAM_SIZE * 2];


static unsigned char *ucpPoint[5]; // 메모리 공간을 구분하는 변수. 이곳에서만 쓰이기 때문에 static

unsigned int uiLoadFlag = 0;


CONTEXT_INFO stOldReg;


COMMAND stCommand[] =

{

{ "CODE", "코드 영역을 봅니다", ViewCode },

{ "DATA", "데이터 영역을 봅니다", ViewData },

{ "STACK", "스택 영역을 봅니다", ViewStack },

{ "REGVIEW", "레지스터를 봅니다", ViewRegister },

{ "LOAD", "실행 파일을 메모리에 적재합니다", OpenExcutable },

{ "CLEAR", "메모리를 비웁니다", MemoryClear },

{ "GO", "적재한 실행 파일을 실행합니다", Go },

{ "EXIT", "종료합니다", Exit },

{ 0, 0 }

};


int main()

{

int a = 0x12345678;


ucpPoint[MEMORY_START] = ucMemory;

ucpPoint[MEMORY_END] = ucMemory + sizeof( ucMemory );


ucpPoint[CODE] = ( unsigned char * )( ( int )( ucMemory+MAX_PROGRAM_SIZE ) & 0xFFFF0000 );

ucpPoint[DATA] = ucpPoint[CODE] + 0x2000;

ucpPoint[STACK] = ucMemory+0x10000;


printf( "Start of memory\t: 0x%08X\n", ucpPoint[MEMORY_START] );

printf( "End of memory\t: 0x%08X\n", ucpPoint[MEMORY_END] );

printf( "CODE\t: 0x%08X\n", ucpPoint[CODE] );

printf( "DATA\t: 0x%08X\n", ucpPoint[DATA] );

printf( "STACK\t: 0x%08X\n", ucpPoint[STACK] );


STST( &stOldReg );


while( 1 )

{

Command();

}


//printf( "0x%08X : %02X\n", &a, MD( &a ) );

//MM( &a, 0xFF );


//printf( "0x%08X : %02X\n", &a, MD( &a ) );

//printf( "0x%08X : %08X\n", &a, a );


//ChaseAddress( ( unsigned char * )&a, 4 );


//PrintRegister( &stOldReg );


//STST( &stReg );

//PrintRegister( &stReg );


return 0;

}


void PrintRegister( CONTEXT_INFO *stpReg )

{

printf( "┌──────RegisterStatus──────┐\n" );

printf( "│EAX : 0x%08X\t", stpReg->eax );

printf( "ECX : 0x%08X│\n", stpReg->ecx );

printf( "│EDX : 0x%08X\t", stpReg->edx );

printf( "EBX : 0x%08X│\n", stpReg->ebx );

printf( "│ESP : 0x%08X\t", stpReg->esp );

printf( "EBP : 0x%08X│\n", stpReg->ebp );

printf( "│ESI : 0x%08X\t", stpReg->esi );

printf( "EDI : 0x%08X│\n", stpReg->edi );

printf( "│EIP : 0x%08X\t", stpReg->eip );

printf( "EFL : 0x%08X│\n", stpReg->efl );

printf( "└───────────────────┘\n\n" );

}


void ChaseAddress( unsigned char * _uCp, int _iSize )

{

unsigned char *m_uCp = _uCp;

int m_count=0;

int i=0;

int m_bytes = 0;


printf( "\n" );

DrawHeader();


while( 1 )

{

if( ( i % 22 == 0 )&&( i != 0 ) )

{

printf( "<Press any key to view more... <q> to exit>" );

if( getch() == 'q' )

{

break;

}

putchar( '\n' );

DrawHeader();

}


printf( "  %08X  ", m_uCp );

for( m_count=0; m_count<=15; m_count++ )

{

if( m_bytes < _iSize )

{

printf( "%02X", MD( ( int * )(m_uCp + m_count) ) );

if( m_count != 15 )

{

putchar(' ');

}

m_bytes = m_bytes + 1;

}

else

{

printf( "  " );

if( m_count != 15 )

{

putchar(' ');

}

}

}

printf( "  " );


for( m_count=0; m_count<=15; m_count++ )

{

if( m_uCp + m_count < _uCp+_iSize )

{

if( 0 == *( m_uCp + m_count ) )

{

printf( "." );

}

else if( 32 > *( m_uCp + m_count )  )

{

printf( "*" );

}

else if( 127 < *( m_uCp + m_count )  )

{

printf( "*" );

}

else

{

printf( "%c", MD( ( int * )(m_uCp + m_count) ) );

}

}

else

{

printf( " " );

}

}

if( m_bytes == _iSize )

{

printf( "\n\n<End of memory.>\n" );

break;

}

putchar( '\n' );

i = i + 1;

m_uCp = m_uCp + 16;

}

printf( "\n\n" );

}


void DrawHeader()

{

int i;


printf( "  Address                          HEX                             ASCII\n" );

printf( "            " );

for( i=0; i<=15; i++ )

{

printf( "%02X", i );

if( i != 15 )

{ putchar(' ');

}

}

printf( "  " );

for( i=0; i<=15; i++ )

{

printf( "%1X", i );

}

printf( "\n" );

}


void Command()

{

int i;

int iRet;


unsigned char ucCommand[30];


fflush( stdin );

printf( "COMMAND> " );

iRet = read( 0, ucCommand, 30 );

ucCommand[iRet-1] = 0;


for( i=0; i<iRet-1; i++ )

{

ucCommand[i] = toupper( ucCommand[i] );

}


i = 0;

while( 1 )

{

if( stCommand[i].fp == 0 )

{

printf( "오류 : 없는 명령어 입니다!\n\n<명령어 목록>\n" );


for( i=0; stCommand[i].fp!=0; i++ )

{

printf( "%s\t: %s\n", stCommand[i].ucpCommand, stCommand[i].ucpDetail );

}

putchar( '\n' );

break;

}


if( strcmp( stCommand[i].ucpCommand, ucCommand ) == 0 )

{

(stCommand[i].fp)();

break;

}

i++;

}

}


void ViewCode()

{

ChaseAddress( ucpPoint[CODE], ucpPoint[DATA]-ucpPoint[CODE] );

return;

}

void ViewData()

{

ChaseAddress( ucpPoint[DATA], ucpPoint[DATA]-ucpPoint[CODE] );

return;

}

void ViewStack()

{

ChaseAddress( ucpPoint[MEMORY_END]-159, 160 );

return;

}

void ViewRegister()

{

CONTEXT_INFO stContext;


STST( &stContext );

PrintRegister( &stContext );

return;

}

void Exit()

{

exit( 0 );

return;

}


void OpenExcutable()

{

int iFd = 0; // File descripter

int iRet;

unsigned int uiTotalCount = 0;

unsigned int iCount = 0;


unsigned char *ucpCursor;

unsigned char *ucpCodeStart;


unsigned char ucFileName[30];


IMAGE_DOS_HEADER *stpDOSHeader;

IMAGE_NT_HEADERS *stpNTHeader;


printf( "파일 이름<실행파일> : " );


iRet = read( 0, ucFileName, 30 );

ucFileName[iRet-1] = 0;


iFd = open( ucFileName, O_RDONLY );


if( iFd < 0 )

{

printf( "\n파일을 열 수 없습니다...\n\n" );

return;

}


MemoryClear();


iRet = read( iFd, ucMemory, MAX_PROGRAM_SIZE );


if( iRet < 0 )

{

printf( "\n파일을 읽을 수 없습니다...\n\n" );

close( iFd );

return;

}


stpDOSHeader = ( IMAGE_DOS_HEADER* )ucMemory;


printf( "파일을 열었습니다.\n" );


if( stpDOSHeader->e_magic != 0x5A4D )

{

printf( "올바른 파일 형식이 아닙니다. 실행 파일을 입력해 주시기 바랍니다.\n\n" );

close( iFd );

return;

}


stpNTHeader = ( IMAGE_NT_HEADERS* )( ucMemory + stpDOSHeader->e_lfanew -1 );


printf( "%d\n", stpNTHeader->OptionalHeader.SizeOfInitializedData );


uiTotalCount = stpNTHeader->OptionalHeader.SizeOfHeaders;

iRet = lseek( iFd, stpNTHeader->OptionalHeader.SizeOfHeaders, SEEK_SET );


MemoryClear();


if( iRet < 0 )

{

printf( "파일 적재 오류!\n" );

close( iFd );

return;

}


iRet = read( iFd, ucpPoint[CODE], SECTION_SIZE );

if( iRet < 0 )

{

printf( "코드 영역 적재 오류!\n" );

close( iFd );

return;

}

uiTotalCount = uiTotalCount + iRet;


iRet = read( iFd, ucpPoint[DATA], SECTION_SIZE );

if( iRet < 0 )

{

printf( "데이터 영역 적재 오류!\n" );

close( iFd );

return;

}

uiTotalCount = uiTotalCount + iRet;


printf( "총 읽어들인 바이트 수 : %d bytes\n", uiTotalCount );


close( iFd );


uiLoadFlag = 1;


return;

}


void MemoryClear()

{

printf( "메모리를 초기화합니다...\n" );

memset( ucpPoint[CODE], 0, ucpPoint[MEMORY_END]-ucpPoint[CODE] );


uiLoadFlag = 0;

}


void Go()

{

CONTEXT_INFO stNewReg = { 0, };


if( uiLoadFlag )

{

stNewReg.eax = ( int )&stOldReg;

stNewReg.eip = ( int )ucpPoint[CODE];

stNewReg.esp = ( int )(ucpPoint[MEMORY_END]+4); // PUSH는 이동하고 값을 넣으므로...


LDST( &stNewReg );


printf( "Kernel Panic\n" );

}

else

{

printf( "프로그램을 적재하시기 바랍니다...\n" );

}

}



3. monitor.asm

3-1. 프로그램의 흐름

1. STST

1. 플래그 레지스터 백업

- 저장하는 차원에서 플래그 레지스터가 변경되어 이를 변경

-> 함수 내 스택에서 고쳐야 한다

2. ESP를 함수의 인자로 이동

- 컨텍스트 구조체가 저장된 메모리를 가르키게 된다

3. ESP의 위치를 10칸 내린다

- 구조체에 직접 값을 넣기 위해

4. PUSHAD를 이용해 다수의 레지스터의 값을 넣는다

- 이 때, ESP는 무시되므로 직접 넣어 주어야 한다

-> ESP는 도중에 이동되면 문제를 일으킬 수 있으므로

5. ESP의 값을 저장한다

-> 함수의 EBP 위치에서 8바이트 떨어진 곳이 ESP의 위치

6. Old EBP의 값을 저장

7. EIP의 값을 Return Address의 값으로 지정

8. 플래그 레지스터 푸쉬

2. LDST

1. ESP를 컨텍스트 구조체가 있는 곳으로 옮긴다.

2. EFL의 값을 읽어온다.

3. 이전 EIP를 EAX에 저장한다

4. EBX에 현재 ESP를 저장한다

5. 과거 ESP로 점프한다.

6. 과거 ESP의 위치에 EAX를 PUSH하여 RA를 덮어쓴다

7. ESP를 다시 복원시켜 현재로 돌아온다

8. ESP를 제외한 모든 값을 복원시켜 STST로 저장한 당시 그대로의 상황을 만든다

- 이 때, ESP를 한 칸 올려 주어야 한다

-> RET할 때, POP된 주소로 점프하는데 올려주지 않으면 제대로 RET되지 않기 때문

3. MD

1. 인자(주소)를 EAX에 넣는다

2. EAX에 EAX의 주소를 따라가서 나오는 값을 다시 넣는다

3. 리턴한다

4. MM

1. 인자(주소)를 EAX에 넣는다

2. BL에 인자(데이터)를 넣는다

3. EAX의 주소에 BL의 값을 넣는다


3-2. 소스

.386

.MODEL FLAT


PUBLIC _STST ; Store Status

PUBLIC _LDST ; Load Status

PUBLIC _MD ; Memory Display

PUBLIC _MM ; Memory Modify


.CODE

_STST PROC NEAR32

PUSH EBP

MOV EBP, ESP


PUSHFD


AND DWORD PTR [EBP-4], 0FFFFFEFFh


MOV ESP, [EBP+8]


ADD ESP, 40


PUSHAD


ADD ESP, 16

;Old EBP, RA, 인자, Main과의 경계

MOV EAX, EBP

ADD EAX, 8


PUSH EAX ; 메인 ESP


PUSH [EBP] ; Old EBP


SUB ESP, 8


PUSH [EBP+4] ; EIP(Return Address)

PUSH [EBP-4] ; EFL


MOV ESP, EBP

POP EBP

RET

_STST ENDP


_LDST PROC NEAR32


MOV ESP, [ESP+4] ; ESP = &Context


POPFD ; EFL = Context.EFL

; 플래그 레지스터에 값을 넣음


POP EAX ; EAX = Context.EIP

; 예전 EIP를 EAX 저장


MOV EBX, ESP ; EBX = Current ESP

; 현재 ESP 백업


MOV ESP, [ESP+12] ; ESP = Old ESP

; 과거 ESP로 점프


PUSH EAX ; Save Old EIP

; 과거 ESP에 EAX를 푸쉬하여 RA덮어씀


MOV ESP, EBX ; ESP = Current ESP

; 백업해둔 ESP를 다시 복원


POPAD ; ESP를 제외한 모든 값을 복원


MOV ESP, [ESP-20] ; Old ESP값을 복원

SUB ESP, 4 ; ESP를 RA위로 올려주어야 한다(RET이 POP하기때문)


RET

_LDST ENDP


_MD PROC NEAR32

PUSH EBP

MOV EBP, ESP


MOV EAX, [EBP+8]

MOV EAX, [EAX]


MOV ESP, EBP

POP EBP

RET

_MD ENDP


_MM PROC NEAR32

PUSH EBP

MOV EBP, ESP


PUSH EBX


MOV EAX, [EBP+8] ; EAX = Address

MOV BL, [EBP+12] ; BL = Data


MOV BYTE PTR [EAX], BL ; *EAX = BL


POP EBX


MOV ESP, EBP

POP EBP

RET

_MM ENDP


END



4. 실행 결과

<명령어 목록>


<바르지 않은 GO 명령>


<실행 파일 적재>


<실행 전 데이터 영역>


<실행 후 데이터 영역>

개요

 최근에 내가 2년밖에 사용안한 노트북이 넘락 LED쪽이 나갔는지 불이 들어오지 않는 상황이 발생하였다. 물이 들어갔나ㅜㅜ;

캡스락은 글자를 직접 쳐보면 알 수 있지만 넘락은 알기 힘들기 때문에(사실 캡스락은 아직 망가지지 않아서) 넘락을 자주 쓰다보니 불편함을 느끼게 되어 트레이에 표시가 되도록 하면 어떨까? 싶어 만들게 되었다.

 처리 구조상 어쩔 수 없이 전역 후킹을 사용하였는데, 단순하게 생각했다가 큰 코 다쳤다. 하지만 인터넷의 힘을 빌려 어떻게 잘 만들었다..만 이상한 오류를 너무 많이 겪고 테스트하다 컴이 뻑나서 소스도 날릴뻔하고 이래저래 많은 일이 있었다! 두번 다시 전역 후킹을...안하진 않겠지만, 나름 도움이 된 것 같다..ㅋㅋ 트레이 아이콘을 없애고 WinSock 등을 함께 쓰면...ㄷㄷ


제작 기간 : 하루

개발 언어 : C++ + Win32API

개발 환경 : VS2010

운영체제 : Windows 7 / Windows XP

기능 : NUM LOCK 키의 입력를 감지하여 현재 상태를 트레이에 띄워 보여준다.

리소스 : 아이콘 에디터로 직접 그렸당!!(뭐가 꼬였는지 내가 원하는 아이콘이 아니라 다른 아이콘이 사용되었다..ㅠ)



사용 화면




실행 파일

NumLock_debug.zip

(압축파일 내 두개의 파일이 함께 있어야 정상 작동됩니다)


 아직 디버그 버전...^^;;;;; 릴리즈로 컴파일하면 오류(?)가 나서 현재 일단 보류하고 프로그램부터 올려둡니다.

시간나면...고칠게요..


컴퓨터를 실행하자마자 실행하려면 그냥 시작 프로그램에 넣도록 합니다.... orz

참고로 윈7에서 트레이가 숨겨지는 경우가 있는데 항상 알림으로 설정해 두면 됩니둥.


+ Recent posts