EmEditor 용 매크로 스크립트

요 녀석은 일정 형식의 DATA 를 인풋해 주면 CREATE TABLE 스크립트를 만들어 주는 녀석이다.

EmEditor 는 매크로를 만들때 JScript 와 VBScript를 사용할수 있다. 나는 VBScript 에는 별로 익숙하진 않으니, JScript 를 선택! 그러나 MS 진영에서는 VBScript 가 더 쓸모가 많구나.

이건 내가 회사에서 쓰는 양식이니 다른사람에겐 유용하진 않겠으나, EmEditor 가 꽤 편리한 녀석을 다시 확인한 것. 그리고, 이건 참고만 하시라.

#title = "makeCreateTableScript"
#tooltip = "makeCreateTableScript"

if(typeof String.prototype.trim !== 'function')
{
	String.prototype.trim = function() {
		return this.replace(/^\s+|\s+$/g,'');
	};
}

document.selection.StartOfDocument();

var lineCount = document.GetLines(eeGetLineView);

var dataTableSpace = "TS_DATA";
var indexTableSpace = "TS_IDX";

var reBound = new RegExp("^#(.+?) (.+)$");
var reField = new RegExp("^(.+?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*)$");
var reIndex = new RegExp("^(.+?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*)$");

var tableScript = "CREATE TABLE %{TABLE_NAME} \n(";
var commentScript = "COMMENT ON TABLE %{TABLE_NAME} IS '';";
var indexScript = "";

var matched = false;

var mode = 0;
var currentTableName = "";
var currentSection = "";

for(var i=1; lineCount>i; ++i)
{
	var str = document.GetLine(i,eeGetLineView);

	var mB = reBound.exec(str);

	if(mB != null)
	{
		if(mB[1].trim() == "table")
		{
			currentTableName = mB[2].trim();;
			tableScript = tableScript.replace(new RegExp("%{TABLE_NAME}","g"),currentTableName);
			commentScript = commentScript.replace(new RegExp("%{TABLE_NAME}","g"),currentTableName);
		}
		else if(mB[1].trim() == "section")
		{
			currentSection = mB[2].trim();
		}
	}

	if(currentSection == "field")
	{
		var mF = reField.exec(str);

		if(mF != null)
		{
			tableScript += "\n\t" + mF[1].trim() + " " + mF[3].trim() + "(" + mF[4].trim() + ") " + ((mF[5].trim() == "Y") ? "NULL," : "NOT NULL,");
			commentScript += "\nCOMMENT ON COLUMN " + currentTableName + "." + mF[1].trim() + " IS '" + mF[2].trim() + "';";
			matched = true;
		}
	}

	if(currentSection == "index")
	{
		var mI = reIndex.exec(str);

		if(mI != null)
		{
			if(mI[3].trim() == "주키")
			{
				indexScript += "\nCREATE UNIQUE INDEX " + mI[1].trim() + " ON " + currentTableName
					+ "\n (" + mI[5].trim() + ") TABLESPACE " + indexTableSpace + ";";
				indexScript += "\nALTER TABLE " + currentTableName + " ADD CONSTRAINT " + mI[1].trim()
					+ "\n  PRIMARY KEY (" + mI[5].trim().replace(new RegExp(" ASC","g"),"").replace(new RegExp(" DESC","g"),"")
					+ ") USING INDEX TABLESPACE " + indexTableSpace + ";";
			}
			else if(mI[3].trim() == "일반")
			{
				indexScript += "\nCREATE INDEX " + mI[1].trim() + " ON " + currentTableName
					+ "\n (" + mI[5].trim() + ") TABLESPACE " + indexTableSpace + ";";
			}
		}

	}

}

tableScript = tableScript.substr(0,tableScript.length-1);

tableScript += "\n) TABLESPACE " + dataTableSpace + ";";

if(matched)
{
	document.selection.EndOfDocument();
	document.write("\n\n");
	document.write(tableScript);
	document.write("\n\n");
	document.write(indexScript);
	document.write("\n\n");
	document.write(commentScript);
}

아랫것은 인풋데이터와 아웃풋 스크립트이다.

#table VIDEO_INFO
#section field
VIDEO_ID    	영상ID	NUMBER	10	N	P
GID         	글러벌ID	VARCHAR2	10	N
VIDEO_USAGE 	영상타입	VARCHAR2	3	Y
VIDEO_FORMAT	영상포멧	VARCHAR2	3	Y
ORDER_NUMBER	순서	NUMBER	2	Y
VIDEO_NAME  	파일명	VARCHAR2	128	Y
FILE_PATH   	파일경로	VARCHAR2	256	Y
VIDEO_URL   	영상URL	VARCHAR2	1024	Y
VIDEO_DESC  	영상설명	VARCHAR2	2000	Y
F_STATUS    	상태	VARCHAR2	3	Y		

#section index
PK_VIDEO_INFO		주키		VIDEO_ID ASC
IDX_VIDEO_INFO_01		일반		GID ASC			

#/table

CREATE TABLE VIDEO_INFO
(
	VIDEO_ID NUMBER(10) NOT NULL,
	GID VARCHAR2(10) NOT NULL,
	VIDEO_USAGE VARCHAR2(3) NULL,
	VIDEO_FORMAT VARCHAR2(3) NULL,
	ORDER_NUMBER NUMBER(2) NULL,
	VIDEO_NAME VARCHAR2(128) NULL,
	FILE_PATH VARCHAR2(256) NULL,
	VIDEO_URL VARCHAR2(1024) NULL,
	VIDEO_DESC VARCHAR2(2000) NULL,
	F_STATUS VARCHAR2(3) NULL
) TABLESPACE TS_DATA;

CREATE UNIQUE INDEX PK_VIDEO_INFO ON VIDEO_INFO
 (VIDEO_ID ASC) TABLESPACE TS_IDX;
ALTER TABLE VIDEO_INFO ADD CONSTRAINT PK_VIDEO_INFO
  PRIMARY KEY (VIDEO_ID) USING INDEX TABLESPACE TS_IDX;
CREATE INDEX IDX_VIDEO_INFO_01 ON VIDEO_INFO
 (GID ASC) TABLESPACE TS_IDX;

COMMENT ON TABLE VIDEO_INFO IS '';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_ID IS '영상ID';
COMMENT ON COLUMN VIDEO_INFO.GID IS '글러벌ID';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_USAGE IS '영상타입';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_FORMAT IS '영상포멧';
COMMENT ON COLUMN VIDEO_INFO.ORDER_NUMBER IS '순서';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_NAME IS '파일명';
COMMENT ON COLUMN VIDEO_INFO.FILE_PATH IS '파일경로';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_URL IS '영상URL';
COMMENT ON COLUMN VIDEO_INFO.VIDEO_DESC IS '영상설명';
COMMENT ON COLUMN VIDEO_INFO.F_STATUS IS '상태';

 

 

Posted in 잡다한 지식 | Tagged , , , | Leave a comment

ansi,unicode,utf8 변환(윈도우용)

// ansi 문자열을 utf8 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline char *ansi_to_utf8(char *p_ansi_str)
{
	wchar_t *p_unicode_str;
	char *p_utf8_str;

	int ansi_str_len = strlen(p_ansi_str);

	int size = 0;

	size = MultiByteToWideChar(CP_ACP, 0, p_ansi_str, -1,NULL,0);

	p_unicode_str = new wchar_t[size];
	ZeroMemory(p_unicode_str,size);

	MultiByteToWideChar(CP_ACP, 0, p_ansi_str, -1,p_unicode_str,size);

	size = WideCharToMultiByte(CP_UTF8, 0, p_unicode_str,-1, NULL,0,NULL,NULL);

	p_utf8_str = new char[size];
	ZeroMemory(p_utf8_str,size);

	WideCharToMultiByte(CP_UTF8, 0, p_unicode_str,-1, p_utf8_str,size,NULL,NULL);

	delete[] p_unicode_str;

	return p_utf8_str;

}

// ansi 문자열을 unicode 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline wchar_t *ansi_to_unicode(char *p_ansi_str)
{
	wchar_t *p_unicode_str;

	int ansi_str_len = strlen(p_ansi_str);

	int size = 0;

	size = MultiByteToWideChar(CP_ACP, 0, p_ansi_str, -1,NULL,0);

	p_unicode_str = new wchar_t[size];
	ZeroMemory(p_unicode_str,size);

	MultiByteToWideChar(CP_ACP, 0, p_ansi_str, -1,p_unicode_str,size);

	return p_unicode_str;
}

// utf8 문자열을 ansi 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline char *utf8_to_ansi(char *p_utf8_str)
{
	wchar_t *p_unicode_str;
	char *p_ansi_str;

	int size = 0;
	size = MultiByteToWideChar(CP_UTF8,0,p_utf8_str, -1,NULL,0);

	p_unicode_str = new wchar_t[size];
	ZeroMemory(p_unicode_str,size);

	MultiByteToWideChar(CP_UTF8, 0, p_utf8_str, -1,p_unicode_str,size);

	size = WideCharToMultiByte(CP_ACP, 0, p_unicode_str,-1, NULL,0,NULL,NULL);

	p_ansi_str = new char[size];
	ZeroMemory(p_ansi_str,size);

	WideCharToMultiByte(CP_ACP, 0, p_unicode_str,-1, p_ansi_str,size,NULL,NULL);

	delete[] p_unicode_str;

	return p_ansi_str;
}

// utf8 문자열을 unicode 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline wchar_t *utf8_to_unicode(char *p_utf8_str)
{

	wchar_t *p_unicode_str;

	int size = 0;
	size = MultiByteToWideChar(CP_UTF8,0,p_utf8_str, -1,NULL,0);

	p_unicode_str = new wchar_t[size];
	ZeroMemory(p_unicode_str,size);

	MultiByteToWideChar(CP_UTF8, 0, p_utf8_str, -1,p_unicode_str,size);

	return p_unicode_str;

}

// unicode 문자열을 utf8 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline char *unicode_to_utf8(wchar_t *p_unicode_str)
{
	char *p_utf8_str;

	int size = 0;

	size = WideCharToMultiByte(CP_UTF8, 0, p_unicode_str,-1, NULL,0,NULL,NULL);

	p_utf8_str = new char[size];
	ZeroMemory(p_utf8_str,size);

	WideCharToMultiByte(CP_UTF8, 0, p_unicode_str,-1, p_utf8_str,size,NULL,NULL);

	return p_utf8_str;
}

// unicode 문자열을 ansi 문자열로 변환함.
// 메모리해제 필요함. delete[]
inline char *unicode_to_ansi(wchar_t *p_unicode_str)
{
	char *p_ansi_str;

	int size = 0;

	size = WideCharToMultiByte(CP_ACP, 0, p_unicode_str,-1, NULL,0,NULL,NULL);

	p_ansi_str = new char[size];
	ZeroMemory(p_ansi_str,size);

	WideCharToMultiByte(CP_ACP, 0, p_unicode_str,-1, p_ansi_str,size,NULL,NULL);

	return p_ansi_str;
}
Posted in 코드창고 | Tagged , , , , , | 1 Comment

아이폰 충전기 급조!

설에 시골에 내려가려고 아침에 버스시간 맞춘다고 급하게 나갔더니 그만 USB 충전기를 챙기지 못했다. 키악~~~~!!!!!! 나같은 녀석은 인터넷,스마트기기없이 단 1초도 못 산다고!

시골집에 USB 포트가 있을까 했지만 그런 외딴 시골집에 USB포트가 있을리가 없지…. 그렇다고 돈들여서 시내까지 나가서 사오는 궁상을 떨긴 싫다. -_-

그런데 마침 눈에띤 5V아답터 ㅋㅋ 아싸 ㅋㅋ 아시다 시피 USB 포트에서 나오는 전압도 5V이다.

USB 핀레이아웃은 다음과 같습니다.

핀번호 할당
1 +5V DC
2 Data -
3 Data +
4 Ground

그래서 탄생한 첫번째 녀석이다.

+,- 5V 인가만으로도 에그는 충전이 되었다. 후레이!! 그러나 아이폰과 아이패는 충전이 되지 않았는데…. 구글링을 해보니 아이폰의 충전회로는 Data +,- 풀업 회로가 따로 필요하다는 것이었다.(아래 그림 참고)

뭐..저항은 구할수가 없지만 비슷한 효과를 내기 위해 다음과 같이 변경… -_-..1,2,3번 핀에 그냥  5V 인가! ㅋㅋ

결론은 아주 잘된다!! 츄릅…그래서 설날을 아이패드와 함께 유익하게 잘 보냈습니다. 밧데리 걱정 없이….쿄쿄..

-주의- 아이패드에서는 위와 같이 할경우 아이패드 내부의 USB 모듈이 손상을 입는거 같습니다. 아이패드가 아이튠즈에서 인식이 되질 않는군요. ㅠㅠ 그래서 수리 맡겼습니다. 근데 아이폰은 괜찮은것 같아요.

Posted in 잡다한 지식 | Tagged | 2 Comments

고객님 안되겠심다 켁

며칠전에 어떤 프로그램에 걸린 패스워드를 우회할수 있는지 문의가 왔었다.

프로그램은 패킹되어 있는것으로 보였고, 암호를 입력해야만 작동하는 방식이었다.

일단 우리 고객님은 비밀번호를 모르신다.

암호화는 SHA-1 으로 되어 있었다. 아래는 SHA-1 암호화 알고리즘의 어셈코드 모습. 역시 복잡하다. 웃긴게 난 이게 SHA-1 인줄도 몰랐다. 머리를 쥐어뜯다. 20바이트 해쉬크기를 가지는 암호화가 뭐가 있나 찾아봤더니 SHA-1 이었다. 전수대입으로 풀어도 무지막지하게 오래 걸리는… -_- 하마터면 나 큰도전 할뻔했다.

CPU Disasm
Address   Hex dump          Command                                  Comments
012386B3    55              PUSH EBP
012386B4    8BEC            MOV EBP,ESP
012386B6    81EC 54010000   SUB ESP,154
012386BC    53              PUSH EBX
012386BD    56              PUSH ESI
012386BE    57              PUSH EDI
012386BF    8DB5 ACFEFFFF   LEA ESI,[EBP-154]
012386C5    8D51 1C         LEA EDX,[ECX+1C]
012386C8    C745 FC 1000000 MOV DWORD PTR SS:[EBP-4],10
012386CF    8B02            MOV EAX,DWORD PTR DS:[EDX]
012386D1    83C2 04         ADD EDX,4
012386D4    8BF8            MOV EDI,EAX
012386D6    8BD8            MOV EBX,EAX
012386D8    81E7 0000FF00   AND EDI,00FF0000
012386DE    C1EB 10         SHR EBX,10
012386E1    0BFB            OR EDI,EBX
012386E3    8BD8            MOV EBX,EAX
012386E5    C1E3 10         SHL EBX,10
012386E8    25 00FF0000     AND EAX,0000FF00
012386ED    0BD8            OR EBX,EAX
012386EF    C1EF 08         SHR EDI,8
012386F2    C1E3 08         SHL EBX,8
012386F5    0BFB            OR EDI,EBX
012386F7    893E            MOV DWORD PTR DS:[ESI],EDI
012386F9    83C6 04         ADD ESI,4
012386FC    FF4D FC         DEC DWORD PTR SS:[EBP-4]
012386FF  ^ 75 CE           JNE SHORT 012386CF
01238701    6A 40           PUSH 40
01238703    8D95 B4FEFFFF   LEA EDX,[EBP-14C]
01238709    5E              POP ESI
0123870A    8B42 2C         MOV EAX,DWORD PTR DS:[EDX+2C]
0123870D    3342 18         XOR EAX,DWORD PTR DS:[EDX+18]
01238710    3342 F8         XOR EAX,DWORD PTR DS:[EDX-8]
01238713    3302            XOR EAX,DWORD PTR DS:[EDX]
01238715    83C2 04         ADD EDX,4
01238718    8BF8            MOV EDI,EAX
0123871A    03C0            ADD EAX,EAX
0123871C    C1EF 1F         SHR EDI,1F
0123871F    0BF8            OR EDI,EAX
01238721    4E              DEC ESI
01238722    897A 34         MOV DWORD PTR DS:[EDX+34],EDI
01238725  ^ 75 E3           JNE SHORT 0123870A
01238727    8B71 10         MOV ESI,DWORD PTR DS:[ECX+10]
0123872A    8B79 14         MOV EDI,DWORD PTR DS:[ECX+14]
0123872D    8B41 08         MOV EAX,DWORD PTR DS:[ECX+8]
01238730    8B51 0C         MOV EDX,DWORD PTR DS:[ECX+0C]
01238733    8D9D ACFEFFFF   LEA EBX,[EBP-154]
01238739    8975 F8         MOV DWORD PTR SS:[EBP-8],ESI
0123873C    8B71 18         MOV ESI,DWORD PTR DS:[ECX+18]
0123873F    897D EC         MOV DWORD PTR SS:[EBP-14],EDI
01238742    895D FC         MOV DWORD PTR SS:[EBP-4],EBX
01238745    C745 F4 1400000 MOV DWORD PTR SS:[EBP-0C],14
0123874C    8BDA            MOV EBX,EDX
0123874E    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
01238751    F7D3            NOT EBX
01238753    23DF            AND EBX,EDI
01238755    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
01238758    23FA            AND EDI,EDX
0123875A    33DF            XOR EBX,EDI
0123875C    8BF8            MOV EDI,EAX
0123875E    C1EF 1B         SHR EDI,1B
01238761    C1E0 05         SHL EAX,5
01238764    0BF8            OR EDI,EAX
01238766    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
01238769    8345 FC 04      ADD DWORD PTR SS:[EBP-4],4
0123876D    03F3            ADD ESI,EBX
0123876F    8B00            MOV EAX,DWORD PTR DS:[EAX]
01238771    03FE            ADD EDI,ESI
01238773    8B75 EC         MOV ESI,DWORD PTR SS:[EBP-14]
01238776    8BDA            MOV EBX,EDX
01238778    C1E3 1E         SHL EBX,1E
0123877B    C1EA 02         SHR EDX,2
0123877E    8D8407 9979825A LEA EAX,[EAX+EDI+5A827999]
01238785    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
01238788    0BDA            OR EBX,EDX
0123878A    FF4D F4         DEC DWORD PTR SS:[EBP-0C]
0123878D    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
01238790    897D EC         MOV DWORD PTR SS:[EBP-14],EDI
01238793    895D F8         MOV DWORD PTR SS:[EBP-8],EBX
01238796  ^ 75 B4           JNE SHORT 0123874C
01238798    8D9D FCFEFFFF   LEA EBX,[EBP-104]
0123879E    C745 F4 1400000 MOV DWORD PTR SS:[EBP-0C],14
012387A5    895D FC         MOV DWORD PTR SS:[EBP-4],EBX
012387A8    8BD8            MOV EBX,EAX
012387AA    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
012387AD    C1EB 1B         SHR EBX,1B
012387B0    C1E0 05         SHL EAX,5
012387B3    0BD8            OR EBX,EAX
012387B5    8BC7            MOV EAX,EDI
012387B7    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
012387BA    33C7            XOR EAX,EDI
012387BC    33C2            XOR EAX,EDX
012387BE    03D8            ADD EBX,EAX
012387C0    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
012387C3    8345 FC 04      ADD DWORD PTR SS:[EBP-4],4
012387C7    0318            ADD EBX,DWORD PTR DS:[EAX]
012387C9    8D8433 A1EBD96E LEA EAX,[ESI+EBX+6ED9EBA1]
012387D0    8B75 EC         MOV ESI,DWORD PTR SS:[EBP-14]
012387D3    8BDA            MOV EBX,EDX
012387D5    897D EC         MOV DWORD PTR SS:[EBP-14],EDI
012387D8    C1E3 1E         SHL EBX,1E
012387DB    C1EA 02         SHR EDX,2
012387DE    0BDA            OR EBX,EDX
012387E0    FF4D F4         DEC DWORD PTR SS:[EBP-0C]
012387E3    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
012387E6    895D F8         MOV DWORD PTR SS:[EBP-8],EBX
012387E9  ^ 75 BD           JNE SHORT 012387A8
012387EB    8D9D 4CFFFFFF   LEA EBX,[EBP-0B4]
012387F1    C745 F4 1400000 MOV DWORD PTR SS:[EBP-0C],14
012387F8    895D FC         MOV DWORD PTR SS:[EBP-4],EBX
012387FB    8B5D F8         MOV EBX,DWORD PTR SS:[EBP-8]
012387FE    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
01238801    33DA            XOR EBX,EDX
01238803    23DF            AND EBX,EDI
01238805    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
01238808    23FA            AND EDI,EDX
0123880A    33DF            XOR EBX,EDI
0123880C    8BF8            MOV EDI,EAX
0123880E    C1EF 1B         SHR EDI,1B
01238811    C1E0 05         SHL EAX,5
01238814    0BF8            OR EDI,EAX
01238816    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
01238819    03DF            ADD EBX,EDI
0123881B    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
0123881E    0318            ADD EBX,DWORD PTR DS:[EAX]
01238820    8345 FC 04      ADD DWORD PTR SS:[EBP-4],4
01238824    8D8433 DCBC1B8F LEA EAX,[ESI+EBX+8F1BBCDC]
0123882B    8B75 EC         MOV ESI,DWORD PTR SS:[EBP-14]
0123882E    8BDA            MOV EBX,EDX
01238830    897D EC         MOV DWORD PTR SS:[EBP-14],EDI
01238833    C1E3 1E         SHL EBX,1E
01238836    C1EA 02         SHR EDX,2
01238839    0BDA            OR EBX,EDX
0123883B    FF4D F4         DEC DWORD PTR SS:[EBP-0C]
0123883E    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
01238841    895D F8         MOV DWORD PTR SS:[EBP-8],EBX
01238844  ^ 75 B5           JNE SHORT 012387FB
01238846    8D5D 9C         LEA EBX,[EBP-64]
01238849    C745 F4 1400000 MOV DWORD PTR SS:[EBP-0C],14
01238850    895D FC         MOV DWORD PTR SS:[EBP-4],EBX
01238853    8BD8            MOV EBX,EAX
01238855    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
01238858    C1EB 1B         SHR EBX,1B
0123885B    C1E0 05         SHL EAX,5
0123885E    0BD8            OR EBX,EAX
01238860    8BC7            MOV EAX,EDI
01238862    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
01238865    33C7            XOR EAX,EDI
01238867    33C2            XOR EAX,EDX
01238869    03D8            ADD EBX,EAX
0123886B    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
0123886E    8345 FC 04      ADD DWORD PTR SS:[EBP-4],4
01238872    0318            ADD EBX,DWORD PTR DS:[EAX]
01238874    8D8433 D6C162CA LEA EAX,[ESI+EBX+CA62C1D6]
0123887B    8B75 EC         MOV ESI,DWORD PTR SS:[EBP-14]
0123887E    8BDA            MOV EBX,EDX
01238880    897D EC         MOV DWORD PTR SS:[EBP-14],EDI
01238883    C1E3 1E         SHL EBX,1E
01238886    C1EA 02         SHR EDX,2
01238889    0BDA            OR EBX,EDX
0123888B    FF4D F4         DEC DWORD PTR SS:[EBP-0C]
0123888E    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
01238891    895D F8         MOV DWORD PTR SS:[EBP-8],EBX
01238894  ^ 75 BD           JNE SHORT 01238853
01238896    8B51 08         MOV EDX,DWORD PTR DS:[ECX+8]
01238899    03D0            ADD EDX,EAX
0123889B    8B41 0C         MOV EAX,DWORD PTR DS:[ECX+0C]
0123889E    8951 08         MOV DWORD PTR DS:[ECX+8],EDX
012388A1    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
012388A4    03C2            ADD EAX,EDX
012388A6    8BD3            MOV EDX,EBX
012388A8    8941 0C         MOV DWORD PTR DS:[ECX+0C],EAX
012388AB    8B41 10         MOV EAX,DWORD PTR DS:[ECX+10]
012388AE    03C2            ADD EAX,EDX
012388B0    8941 10         MOV DWORD PTR DS:[ECX+10],EAX
012388B3    8B41 14         MOV EAX,DWORD PTR DS:[ECX+14]
012388B6    03C7            ADD EAX,EDI
012388B8    5F              POP EDI
012388B9    8941 14         MOV DWORD PTR DS:[ECX+14],EAX
012388BC    8B41 18         MOV EAX,DWORD PTR DS:[ECX+18]
012388BF    03C6            ADD EAX,ESI
012388C1    5E              POP ESI
012388C2    8941 18         MOV DWORD PTR DS:[ECX+18],EAX
012388C5    5B              POP EBX
012388C6    C9              LEAVE
012388C7    C3              RETN

단순히 암호 입력만 우회하면 될줄 알았는데, 암호 우회만으로는 프로그램이 메모리참조 오류를 뱉으며 죽어버렸다.

자세히 보니 입력된 암호를 토대로 복호화를 하고 있었다. 복호화 대상은 어딘가의 메모리 주소이다. 복호화된 주소를 참조하다 오류가 났기 때문이다.

일단 암호화 하는 부분의 어셈코드이다.

CPU Disasm
Address   Hex dump          Command                                  Comments
0117855B    55              PUSH EBP
0117855C    8BEC            MOV EBP,ESP
0117855E    81EC 08020000   SUB ESP,208                              ; 지역변수 할당 공간 확보
01178564    57              PUSH EDI
01178565    EB 01           JMP SHORT 01178568
01178567    90              NOP
01178568    EB 01           JMP SHORT 0117856B
0117856A    90              NOP
0117856B    33FF            XOR EDI,EDI
0117856D    397D 14         CMP DWORD PTR SS:[EBP+14],EDI            ; 패스워드 길이 체크 0인지 아닌지.
01178570    75 07           JNE SHORT 01178579                       ; 0이 아니면 점프..
01178572    33C0            XOR EAX,EAX                              ; EAX 를 NULL 로 만들고
01178574    E9 2A010000     JMP 011786A3                             ; 0 이면 함수를 빠져나감..
01178579    53              PUSH EBX                                 ; 그래 요기..
0117857A    56              PUSH ESI
0117857B    EB 01           JMP SHORT 0117857E
0117857D    90              NOP
0117857E    33C0            XOR EAX,EAX
01178580    BE 00010000     MOV ESI,100                              ; ESI 에 100 저장. 10진수 256임.
01178585    EB 01           JMP SHORT 01178588                       ; 256 번 루프를 돌면서 EBP-104 부터 0~ 0x256 을 모두 채움.
01178587    90              NOP
01178588    888405 FCFEFFFF MOV BYTE PTR SS:[EAX+EBP-104],AL
0117858F    40              INC EAX
01178590    3BC6            CMP EAX,ESI
01178592  ^ 72 F1           JB SHORT 01178585
01178594    EB 01           JMP SHORT 01178597
01178596    90              NOP
01178597    33C0            XOR EAX,EAX
01178599    33C9            XOR ECX,ECX
0117859B    3B45 14         CMP EAX,DWORD PTR SS:[EBP+14]            ; 입력된 암호길와 같은지 아닌지 체크
0117859E    75 02           JNE SHORT 011785A2                       ; 같지 않으면 쩜프.
011785A0    33C0            XOR EAX,EAX                              ; EAX 를 0으로 만들고 다시 처음부터 복사할 채비를 함...
011785A2    EB 01           JMP SHORT 011785A5
011785A4    90              NOP
011785A5    8B55 10         MOV EDX,DWORD PTR SS:[EBP+10]            ; 입력된 패스워드 버퍼주소(스택)
011785A8    8A1410          MOV DL,BYTE PTR DS:[EDX+EAX]             ; 256 번 루프를 돌면서 [EBP-208]에 패스워드 버퍼에 있는값을 복사한다.
011785AB    40              INC EAX
011785AC    88940D F8FDFFFF MOV BYTE PTR SS:[ECX+EBP-208],DL
011785B3    41              INC ECX
011785B4    3BCE            CMP ECX,ESI
011785B6  ^ 72 E3           JB SHORT 0117859B
011785B8    897D 14         MOV DWORD PTR SS:[EBP+14],EDI            ; 패스워드 입력 길이를 그냥 0으로 만드넹?
011785BB    B8 FF000000     MOV EAX,0FF                              ; 255
011785C0    EB 01           JMP SHORT 011785C3
011785C2    90              NOP
011785C3    8A943D FCFEFFFF MOV DL,BYTE PTR SS:[EDI+EBP-104]         ; EBP-104+i 로부터 1바이트씩 읽어온다.
011785CA    8B5D 14         MOV EBX,DWORD PTR SS:[EBP+14]
011785CD    8A8C3D F8FDFFFF MOV CL,BYTE PTR SS:[EDI+EBP-208]         ; EBP-208+i 로부터 1바이트씩 읽어온다.
011785D4    8DB43D FCFEFFFF LEA ESI,[EDI+EBP-104]                    ; EBP-104+i 의 버퍼주소를 저장
011785DB    03DA            ADD EBX,EDX                              ; EBX += EDX; 0 + 12F100
011785DD    03CB            ADD ECX,EBX                              ; ECX += EBX; 131 + EBX
011785DF    23C8            AND ECX,EAX                              ; 1바이트만 남기기위하여...
011785E1    894D 14         MOV DWORD PTR SS:[EBP+14],ECX            ; 요걸 길이 부분에?....
011785E4    EB 01           JMP SHORT 011785E7
011785E6    90              NOP
011785E7    EB 01           JMP SHORT 011785EA
011785E9    90              NOP
011785EA    8A9C0D FCFEFFFF MOV BL,BYTE PTR SS:[ECX+EBP-104]         ; EBP-104 버퍼에서 31 만큼 떨어진곳에서 1바이트 읽음
011785F1    8D8C0D FCFEFFFF LEA ECX,[ECX+EBP-104]                    ; 그 주소를 저장함..
011785F8    47              INC EDI                                  ; ++i
011785F9    881E            MOV BYTE PTR DS:[ESI],BL
011785FB    81FF 00010000   CMP EDI,100                              ; 100(256) 에 도달했는지 비교
01178601    8811            MOV BYTE PTR DS:[ECX],DL
01178603  ^ 72 BB           JB SHORT 011785C0
01178605    33FF            XOR EDI,EDI
01178607    897D 14         MOV DWORD PTR SS:[EBP+14],EDI            ; 패스워드 사이즈에 다시 0을...ㅎㅎ
0117860A    50              PUSH EAX
0117860B    90              NOP
0117860C    90              NOP
0117860D    90              NOP
0117860E    90              NOP
0117860F    90              NOP
01178610    90              NOP
01178611    90              NOP
01178612    90              NOP
01178613    90              NOP
01178614    90              NOP
01178615    90              NOP
01178616    90              NOP
01178617    90              NOP
01178618    90              NOP
01178619    90              NOP
0117861A    90              NOP
0117861B    90              NOP
0117861C    90              NOP
0117861D    58              POP EAX
0117861E    397D 0C         CMP DWORD PTR SS:[EBP+0C],EDI            ; 암호화된 버퍼의 크기가 0인지 검사
01178621    897D 10         MOV DWORD PTR SS:[EBP+10],EDI            ; 입력된 패스워드 버퍼주소를 0으로 만듦
01178624    76 64           JBE SHORT 0117868A                       ; 0 보타 같거나 작으면 점프
01178626    47              INC EDI                                  ; 증가
01178627    23F8            AND EDI,EAX                              ; 255 를 넘어가면 0으로 만들기 위함인듯
01178629    EB 01           JMP SHORT 0117862C
0117862B    90              NOP
0117862C    8A943D FCFEFFFF MOV DL,BYTE PTR SS:[EDI+EBP-104]         ; 0 번째 인덱스 부터가 아닌 1번째 인덱스부터 시작한다.
01178633    8D8C3D FCFEFFFF LEA ECX,[EDI+EBP-104]                    ; 그 주소를 저장함
0117863A    8ADA            MOV BL,DL
0117863C    035D 14         ADD EBX,DWORD PTR SS:[EBP+14]
0117863F    23D8            AND EBX,EAX
01178641    8BF3            MOV ESI,EBX
01178643    8975 14         MOV DWORD PTR SS:[EBP+14],ESI
01178646    EB 01           JMP SHORT 01178649
01178648    90              NOP
01178649    EB 01           JMP SHORT 0117864C
0117864B    C7              DB C7                                    ; Unknown command
0117864C    8A9C35 FCFEFFFF MOV BL,BYTE PTR SS:[ESI+EBP-104]
01178653    8DB435 FCFEFFFF LEA ESI,[ESI+EBP-104]
0117865A    8819            MOV BYTE PTR DS:[ECX],BL
0117865C    EB 01           JMP SHORT 0117865F
0117865E    90              NOP
0117865F    8816            MOV BYTE PTR DS:[ESI],DL
01178661    EB 01           JMP SHORT 01178664
01178663    90              NOP
01178664    EB 01           JMP SHORT 01178667
01178666    90              NOP
01178667    8A09            MOV CL,BYTE PTR DS:[ECX]
01178669    8B75 08         MOV ESI,DWORD PTR SS:[EBP+8]             ; 암호화된 버퍼의 내용 BA267E
0117866C    8B5D 10         MOV EBX,DWORD PTR SS:[EBP+10]
0117866F    03CA            ADD ECX,EDX
01178671    23C8            AND ECX,EAX                              ; eax = 0xff
01178673    03F3            ADD ESI,EBX
01178675    8A8C0D FCFEFFFF MOV CL,BYTE PTR SS:[ECX+EBP-104]
0117867C    300E            XOR BYTE PTR DS:[ESI],CL
0117867E    EB 01           JMP SHORT 01178681
01178680    90              NOP
01178681    43              INC EBX
01178682    3B5D 0C         CMP EBX,DWORD PTR SS:[EBP+0C]            ; 루프의 끝인지 판단..
01178685    895D 10         MOV DWORD PTR SS:[EBP+10],EBX            ; 입력된 암호 버퍼의 공간에 복사..
01178688  ^ 72 9C           JB SHORT 01178626
0117868A    50              PUSH EAX
0117868B    90              NOP
0117868C    90              NOP
0117868D    90              NOP
0117868E    90              NOP
0117868F    90              NOP
01178690    90              NOP
01178691    90              NOP
01178692    90              NOP
01178693    90              NOP
01178694    90              NOP
01178695    90              NOP
01178696    90              NOP
01178697    90              NOP
01178698    90              NOP
01178699    90              NOP
0117869A    90              NOP
0117869B    90              NOP
0117869C    90              NOP
0117869D    58              POP EAX
0117869E    6A 01           PUSH 1                                   ; true 인듯..
011786A0    58              POP EAX
011786A1    5E              POP ESI
011786A2    5B              POP EBX
011786A3    5F              POP EDI
011786A4    C9              LEAVE
011786A5    C3              RETN

분석해 보니 상당히 복잡한 알고리즘.. 요걸 C 코드로 바꿔보았다. 인간 디컴파일러 -_-v

int unknow_func(
	unsigned char *encrypted_buf_ptr, /* 암호화된 버퍼의 주소 [EBP + 8] */
	int encrypted_buf_size,  /* 암호화된 버퍼의 크기(216 BYTE) [EBP + 0C] */
	unsigned char *password_buf_ptr,  /* 입력된 암호 버퍼의 주소 [EBP + 10] */
	int password_buf_size    /* 입력된 암호의 길이 [EBP + 14] */
)
{
	unsigned char seed_table[260] = {0,};
	unsigned char xor_key_table[260] = {0,};

	if(password_buf_size == 0)
	{
		return 0;
	}

	for(int i=0; 256>i; ++i)
	{
		xor_key_table[i] = i;
	}

	printf("XOR_KEY_TABLE 1 : \n");
	for(int i=0; i<256; ++i)
	{
		if(i % 16 == 0) printf("\n");
		printf("%02X ", (unsigned char)xor_key_table[i]);
	}
	printf("\n");

	printf("SEED_TABLE 2 : \n");

	int ref = 0;
	for(int i=0; 256>i; ++i)
	{
		if(ref==password_buf_size) ref=0;
		seed_table[i] = password_buf_ptr[ref++];

		if(i % 16 == 0) printf("\n");
		printf("%02X ", (unsigned char)seed_table[i]);
	}

	printf("\n");

	unsigned int start=0;
	unsigned int mask = 0x000000FF;

	for(int i=0; 256>i; ++i)
	{

		unsigned int xor_key_val1 = xor_key_table[i];
		unsigned int tmp = start;

		unsigned int seed_val = seed_table[i];
		unsigned char *xor_key_addr1 = xor_key_table + i;

		tmp += xor_key_val1;
		seed_val += tmp;
		seed_val &= mask;

		start = seed_val;

		unsigned char xor_key_val2 = xor_key_table[seed_val];
		unsigned char *xor_key_addr2 = xor_key_table + seed_val;

		*((unsigned char *)xor_key_addr1) = xor_key_val2;
		*((unsigned char *)xor_key_addr2) = xor_key_val1;

	}

	printf("XOR_KEY_TABLE 3 : \n");
	for(int i=0; i<256; ++i)
	{
		if(i % 16 == 0) printf("\n");
		printf("%02X ", (unsigned char)xor_key_table[i]);
	}
	printf("\n");

	unsigned int start2 = 0;
	unsigned int encrypted_buf_ref = 0;

	int i = 0;
	while(true)
	{
		encrypted_buf_ref = i;
		if(encrypted_buf_size<=i)
		{
			break;
		}

		++i;

		i &= mask;

		unsigned char xor_key_val1 = xor_key_table[i]; // 0 이 아닌 1부터 시작..
		unsigned char *xor_key_addr1 = xor_key_table + i; // ECX

		unsigned int tmp1 = xor_key_val1;

		tmp1 += start2;
		tmp1 &= mask;

		start2 = tmp1;

		unsigned char xor_key_val2 = xor_key_table[start2];
		unsigned char *xor_key_addr2 = xor_key_table + start2; // ESI

		*xor_key_addr1 = xor_key_val2;
		*xor_key_addr2 = xor_key_val1;

		unsigned int tmp2 = *xor_key_addr1;
		unsigned char *encrypted_buf_ptr_tmp = (unsigned char *)encrypted_buf_ptr;

		tmp2 += xor_key_val1;
		tmp2 &= mask;

		encrypted_buf_ptr_tmp += encrypted_buf_ref;

		unsigned char xor_key = xor_key_table[tmp2];
		*((unsigned char *)encrypted_buf_ptr_tmp) ^= xor_key;

		++encrypted_buf_ref;

		if(encrypted_buf_ref < encrypted_buf_size)
		{
		}
		else
		{
			break;
		}

	}

	printf("XOR_KEY_TABLE 4 : \n");
	for(int i=0; i<256; ++i)
	{
		if(i % 16 == 0) printf("\n");
		printf("%02X ", (unsigned char)xor_key_table[i]);
	}
	printf("\n");

	return 1;
}

알고보니…이게 RC4 암/복호화 알고리즘이라고 한다. 풀수없는………..젠장..

고객님..안되겠심미다.. 포기요~ 켁

Posted in 리버즈엔지니어링 | Tagged , , , | Leave a comment

간단히 만들어본 아이폰 탐색기

저도 개발자인 이상 아이폰에서의 개발은 피할 수가 없는것 같습니다. ㅋㅋ

당장은 복잡한것은 만들기 힘들겠고, 뭔가를 만들어 팔아보겠다는 생각보다 아이폰을 좀 손봐주고 싶은 욕구가 생겼습니다.

탈옥하면 간단하겠지만 탈옥하지 않고, 아이폰의 시스템을 주무를 수 있을까 하는 생각에 시도해 봤습니다.

제일 간단하게 system 류 함수를 테스트 해봤습니다.

간단하게 whoami 를 실행하는거였는데 return 값이 32512 인가? (기억이 잘…테스트하다가 등산갔다 와서;;) 가 자꾸 반환되더군요. system 함수는 인자에 NULL 을 주면 sh 사용 가능유무를 확인할수 있습니다. NULL 을 줬을때 0 이 반환되면 sh 를 사용할수 없다는 것이지요. 결론은 0 이 반환되었습니다. /bin/sh 가 없을 가능성에 무게가 실어졌죠.. 결론적으로 내부적을 /bin/sh 를 이용한 시스템콜은 사용할 수 없다는 얘기가 되겠죠.

일단 실행파일이 있는지 없는지 조차 모르는 상태에서 더이상 연구가 어려울것 같아서 디렉터리를 살펴볼수 있는 간단한 어플을 만들어서 아이폰에 올려봤습니다. 물론 개발자 라이센스가 있어야 가능합니다.

뭐..재미난 장난감을 만들었네요. 출근하면서 여기저기 살펴봐야겠습니다. 수확이 있을런지…

 에..근데 이게 나중에 알고 보니 누군가가 구글코드에서 프로젝트로 진행하고 있었군요 -_-; 쩝…

 

Posted in 잡다한 지식 | Leave a comment

쿠키유출이 위험한 이유

웹개발하시는 분들은 세션과 쿠키에 대해서 잘 알것입니다.

사실 이 두가지는 서로 밀접한 관계를 가지고 있습니다.

또한 웹에서의 세션은 사용자의 정보와 밀접한 관계를 가지고 있습니다. 사용자가 로그인한 상태인지 사용자 인증을 이 세션을 통해서 하니까요.

세션은 생성과 함께 클라이언트측에 세션에 대한 키(KEY) 를 주게 되어 있습니다. 줄때 그냥 주는것도 아니고 브라우저에게 해당 키를 쿠키로 굽도록 명령합니다. 바로 이게 세션키입니다.

일단 구워진 쿠키는 해당 도메인 내에서만 유효하고, 페이지를 돌아다닐때마다 쿠키값을 서버로 전송합니다. 그중 세션에 대한 키값을 골라내어 세션과 맵핑을 하는것이죠.

이 세션키는 정의하기 나름이고, 딱히 정해진 표준은 없습니다. 기본적으로 PHP는 PHPSESSID, JSP의 경우 JSESSIONID 식의 이름으로 세션키를 쿠키로 저장합니다. 보통 이런 쿠키들은 브라우저가 닫힘과 동시에 사라지는 옵션으로 생성됩니다.

과연 브라우저측의 쿠키가 없어지면 서버측 세션도 없어질까요?. 불행히도 아직은 서버측에서 클라이언측의 브라우저가 살아있는지 죽었는지 알 수 있는 방법이 없습니다. 그래서 만약에 어떤 사용자가 로그인후에 브라우저를 닫아도 세션키는 사라질지 모르겠지만 서버에는 여전히 사용자 세션이 남아 있다는 것입니다. 보통 세션은 사용자와 서버간의 연결유지목적으로 사용하기 때문에, 일정 시간 동안 갱신되지 않으면 세션이 폐기되도록 되어 있습니다. 그래서 로그인후 아무것도 하지 않다가 다시 페이지를 로딩하면 세션이 사라지기 때문에 로그아웃 되어버리는 것이죠.

문제는 여기에 보안허점이 있다는 것입니다. 남의 세션키를 내것에 대체시킨다면? 맞습니다. 바로 내가 남이 되는것이죠.

실제로 국내 유명 포털인 N 모에서 테스트 해봤습니다. 로그인후 쿠키정보를 취득한 다음에 브라우저를 모두 닫고 아래와 같이 쿠키정보를 입력하였습니다.

 

그리고 새로고침 하니 실제로 로그인한 상태가 되었네요. 하지만 메일이나 쪽지 같은데 접근은 하지는 못했습니다.

 

실험 삼아 N 모사 메일쪽을 좀더 테스트를 해보니 보안구멍이 발견되었네요. N 모사에 이 사실을 알려줘야 하는건지… 익명의 사용자가 N 모사 메일 사용자에게 메일을 보내서 N 모사 메일 사용자의 쿠키를 훔쳐 N 모사 메일 사용자로 로그인 후 메일을 훔쳐 볼 수가 있었습니다.

아래는 수집한 쿠키의 모습이고,

 

다음은 해당 쿠키를 적용하는 스크립트


 
그리고 로그인한 모습입니다. 물론 제 계정입니다 ^^; 아래 화면은 같은 PC에서 테스트 한것입니다.

HTML 태그 사용을 허용 하는 경우 자바스크립트를 완벽히 필터링 하지 않는 한 보안구멍은 어쩔수 없이 생기는 것 같습니다.

네이버 메일의 경우 좀더 테스트를 해보았습니다. 같은 아이피로 접근되는 경우면 위의 공격이 먹히지만, IP가 다른 곳에서 위와 같이하면 인증을 다시 하도록 되어 있네요. 이렇게 막아 놓았다면 별 문제는 없어보입니다만. 사설망으로 구축되어 있는곳도 안전한지 모르겠네요. 이건 또 집에서 테스트를 해본뒤에 업데이트 하겠습니다.

하지만 네이버 메일처럼 IP체크와 같이 별도의 체크를 하지 않을 경우에는 상당히 위험할수 있습니다.

자바스크립트 폼 체크 우회 글도 참고하시기 바랍니다.

Posted in 보안 | Leave a comment

프로세스 목록 구하기

MS 에 있는 소스를 VS2010 으로 돌린것.

EnumProc

Posted in 코드창고 | Leave a comment

자바스크립트 폼체크 우회

폼 체크(form validation)

form 입력 값들이 제대로 입력 되었는지 검사하는 것을 의미합니다. 사용자가 무슨 값을 입력할지도 모르고, 보안 및 데이터 정규화 때문에 필요한 부분에 강력하고 정확하게 해야 합니다.

대부분 클라이언트의 브라우저에서 체크를 하고, 때에 따라서 서버단으로 넘어오는 값을 체크하는 경우도 있고, 그렇지 않은 경우도 있습니다.

  • 클라이언트 브라우저에서 자바스크립트 등을 사용하여 체크.
  • 서버단에서 체크.

제일 좋은 방법은 양쪽 모두에서 체크를 하거나 2번만 하는 것입니다. 하지만 그렇지 않은 경우도 있는데 대부분 초보프로그래머 들에 의해서, 모르기 때문에 1번 단에서만 체크하고 끝나는 경우도 있습니다. 2번만 체크하는 경우는 국내에서는 좀 드물지만 외국에서는 폼 서브밋 후에 입력값이 유효하지 않음을 알려주는 경우가 꽤 많습니다.

하지만 1번과 2번을 모두 적용하기 에는 유지하기가 좀 귀찮아 지겠죠. 어떤 필드의 입력값 체크 루틴이 바뀌면 1번과 2번 모두를 수정해 줘야 하니까요. 그래서 외국에서는 체크루틴을 한지점에서 하도록 2번에만 넣은 곳이 좀 되는 것 같습니다.

오늘 보안에 대해서 말해 드릴 부분은 1번만 적용했을 때 어떤 위험성이 있는지에 대한 것입니다.

파일 업로드 체크

파일을 업로드 할 때는 반드시 확장자 체크를 해야 합니다. 아주 기초적인 것이지만 이름 꽤나 날리신분도 이 업로드 체크를 무시했다가 크게 혼난 적이 있습니다. 물론 서버단에서 체크한다면 크게 문제되지는 않을것입니다. 문제는 클라이언트 브라우저 단에서만 파일 확장자 체크를 한 경우이겠죠.

공격

때에 따라서는 공격도 가능해 집니다. 필드중에 뷰페이지에서 HTML 필터링을 하지 않는 필드의 경우 불특정 누군가의 쿠키를 훔치거나 다수가 보는 페이지의 경우 기능을 일시적으로 마비 시킬수 있는 스크립트 코드를 삽입할 수도 있습니다. 특히 쿠키의 경우에는 사용자의 세션과 연결될 수 있으므로 사태가 심각해 질 수 있습니다.

데이터 정규화 깨짐

데이터는 데이터가 일관성 있게 존재할 때 그 가치가 있고, 제대로 표시될 수 있음을 보장 할 수가 있습니다. 그런데 이 정규화가 깨진다면? 만약에 정규화에 심각하게 의존하는 소스코드가 있다면 아마도 그 부분에서는 오류가 발생할 수도 있음을 의미합니다. 예를 들면 소스상에서는 그 데이터가 무조건 6자일 것으로 예상하고 프로그램을 만들었으나 7자 이상이거나 할 경우 에러가 발생하거나 프로그램이 오동작 할 수도 있음을 의미합니다. 이 경우 금방 원인을 찾을 수도 있고, 프로그래머를 잠 못 이루게 할 수도 있습니다.

어떻게?

위의 모든 것을 야기시키는 방법은 의외로 매우 간단합니다. 바로 브라우저의 주소 입력창을 통해서 스크립트 코드를 실행하는 방법이죠. 매우 접근이 편하고 간단한 해킹 도구인 셈입니다. 별도의 프로그램 없이도, 지금 내가 보는 웹화면을 조작할 수 있는 최고의 방법인 셈이죠.

간단하게 제 블로그를 가지고 테스트 해보도록 하겠습니다. 이글을 작성할 때 제 블로그는 텍스트큐브라는 블로그툴을 사용하고 있습니다.

간단한 예로 글의 배경색을 붉은 색으로 바꿔보겠습니다.

뭐 이 정도까지는 아무런 피해도 주지 않기 때문에 그냥 장난에 불과하겠습니다. 위와 같이 void 를 사용하지 않으면 저렇게 바뀐 화면을 볼 수 없습니다. 

다음은 제가 자주가는 P모 커뮤니티에 댓글 장난을 친 모습입니다.

그냥 댓글을 입력하면 아래와 같이 내용입력 필수라는 얼럿창이 뜹니다.

아래 화면은 그냥 무시하고 아무 내용 없이 댓글을 단 모습입니다.

위와 같은 방법을 이용해서 스크립트 삽입 후 다른 사용자의 쿠키를 가로챈다면 정말 심각한 것이죠. 실제로 스크립트를 삽입해서 실행될 포인트를 찾는 것은 순전히 경험입니다. 보통은 사용자에게 입력 받는 모든 데이터를 HTML 엔터티 필터링을 하여 보여주진 않으니까요. 구멍이 생기기 마련입니다.

일부 게시판 중에서는 불특정 다수의 사용자들에게 Javscript 사용을 사용 가능하도록 하는 경우가 있는데 이 또한 상당히 위험합니다. XSS(크로스사이트 스크립팅) 에 의한 쿠키 하이재킹이 가능해지기 때문이죠. 쿠키 하이재킹은 곧 세션 하이재킹과 바로 이어지므로 보안상 상당히 위험해 집니다.

다음 시간에는 이 부분을 한번 다뤄 보도록 하겠습니다.

Posted in 보안 | Leave a comment

CreateInstance 의 결과가 계속 FAILED 가 나오네..

누군가가 오래전에 작성한 프로그램을 사용할 일이 있었다.

Windows XP,Windows 7 에서 잘 돌아가는 프로그램이 Windows 2003 에서 돌아가지 않는다.

프로그램은 ADODB 를 사용한다.

Connection 개체를 CreateInstance 할때부터 FAILED 이다.

뭐가 문제일까 한참 삽질했다.

구글링을 하다보니 삽질할때만 해도 무심코 지나쳤던 함수명이 눈에 띈다..

바로 뇌리를 스치고 지나가는 무언가가 있었다.

COM 서비스를 이용할때는 COM 서비스를 이용하는 스레드마다 CoInitialize 나 CoInitializeEx 함수 를 호출해 줘야 한다는것을 말이다.

차라리 각각의 운영체제마다 차이 없이 모두 동작이 안됐다면 찾기 쉬웠을텐데.. 차이가 나는 바람에 갈피를 못잡은거 같다.

그러나 윈도우 운영체제마다 동작에 차이가 나는것은 조금 이상하긴 하다.

아무튼 문제해결은 했다.

Posted in 오늘의 버그 | Leave a comment

RS232 디버깅의 방법

RS232 통신의 디버깅 방법은 몇가지가 있습니다.

1. 컴퓨터 2대를 서로 연결하기.
2. 널 모뎀 에뮬레이터를 설치하기.
3. 장비와 직접 물려 테스트하기.

1번과 2번의 경우는 source 에서 보낸 데이터가 destination 으로 전달이 정확히 되는지 여부를 디버깅 하기 편합니다.

3번의 경우는 여분의 RS232 포트로 출력을 내보내거나 7세그먼트나 다이오드를 조작해 보는 방법이 있겠죠.

2번의 경우에는 com0com 이라는 open source 프로젝트가 존재 합니다. sourceforge 에서 검색하여 다운로드 받을 수 있습니다.

http://com0com.sourceforge.net/

이녀석은 가상 COM 쌍을 생성해 줍니다.

예를 들면 COM6 <==> COM7 이런식으로 연결된 쌍을 생성해 주죠.

1번이나 3번과 같이 별도의 장비가 필요하지 않기 때문에 편합니다.

데이터를 보냈는데 데이터를 받는 쪽에서 깨진데이터를 받는다면, 양쪽의 통신 설정이 동일하게 되었는지 체크해 봐야 합니다. 가장 흔한 경우가 보레이트(baudrate) 설정이 잘못된 경우이죠.

그렇지 않다면 시그널 그라운드가 제대로 연결이 되었는지 체크해야 합니다. DB9핀의 경우 5번 핀이 시그널 그라운드로 사용되는데 쌍방이 연결이 부실할 경우 데이터가 제대로 안받아 질수 있습니다.

RS232 의 경우 1가닥의 신호선을 통해 TTL 레벨 통신을 합니다. 그렇기 때문에 사용할수 있는 거리가 짧습니다. 5미터 이상을 연결해야 된다면 RS422 통신을 고려해야 합니다.

Posted in 잡다한 지식 | 1 Comment