목차

반응형

지뢰찾기를 자동으로 풀어버리는 프로그램을 만든다.

지뢰찾기 - 리버싱

을 먼저 읽어보면 도움이 될듯.

핵심원리

1. 지뢰찾기의 지뢰 정보를 가지고 있는 메모리 덤프를 찾음.

2. 지뢰정보를 받아옴.

3. 지뢰찾기 프로그램에 지뢰가 아닌 부분을 모두다 마우스 클릭하는 입력을함.


프로그램 폼


메모리 덤프를 읽어오는 부분 최대크기의 지뢰판을 형성하면 최대 864의 크기만큼 담기므로 864로 하였다.


while(true)
{
 //행 populate
 if (buffer[x + y * 32] + buffer[x + 1 + y * 32] != 0x20)//의미있는 열임.
 {
     while (true)
     {
         //열 populate
         //buffer[x + y * 32] 주소임
         if (buffer[x + y * 32] != 0x10)
         {
             if (buffer[x + y * 32] != 0x8F)
                click(x, y);
             x++;
         }
         else
         {
             y++;
             x = 1; 
             break;
         }
     }
 }
 else
     break;
}

지뢰정보를 어떻게 읽어올지 고민을 해봤는데

1,1에서 x좌표를 계속 증가시키다가 0x10(지뢰아님) 0x8F(지뢰) 둘다 아닌경우 다음 행으로 넘어감.



지뢰찾기에 마우스 이벤트를 보내는 부분.

지뢰한블록당 32px이므로 칸단 16px씩 이동하면 된다.(단위가 px인지는 모르겠지만 하여튼 들어맞음)

또한 시작지점은 18,60정도로하면 1,1의 지뢰부분이다.

그리고 가장중요한건데 메시지를 보낼때 이동할 좌표값을 넣는건데 쉬프트 연산자가 필요하다

x와 y로 이루어진 값들을 하나의 값으로 표현한뒤에 그것을 보내줘서 인식시키는데

int value = (y_start + (y-1)*16 << 16) + x_start + (x-1)*16;

            SendMessage(process.MainWindowHandle, 0x20, (uint)value, 0x000000001);

            SendMessage(process.MainWindowHandle, 0x20, (uint)value, 0x020100001);

            PostMessage(process.MainWindowHandle, 0x201, 0x000000001, (uint)value);

            PostMessage(process.MainWindowHandle, 0x202, 0x000000000, (uint)value);

보면 value가 x와 y로 이루어진 값이다.

직접 microsoft spy++을 봐보면 좌표부분의 데이터를 전송할때 0x???????? 이런식으로 보낸다.

그중에 앞의 4개의 ????가 y좌표를 나타내고 뒤의 ????가 x좌표를 나타낸다. 물론 16진수로 나타내어져있다.

따라서 x와 y의 값으로 나타내기위해서는 먼저 y좌표에 2^16을 곱하여 왼쪽으로 4칸이동시키고 x좌표값은 그냥 더해주면된다. 16진수로 바꿔줘야하고

그렇게 보내면 프로그램이 원하는 좌표로 이동하여 보내진다.



minesweeper.zip

해당 프로젝트 파일



반응형

'보안 > 리버싱' 카테고리의 다른 글

reversing - minesweeper  (0) 2017.01.25
반응형

winmine.exe


지뢰찾기 매크로를 만들려고 한다.

올리디버거로 먼저 지뢰찾기를 분석하였다.


http://www.morwire.com/index.php/reverse-engineering/5-introduction-to-reversing-minesweeper

이곳에서 자세한 정보를 얻을 수 있었음.

위의 글은 지뢰찾기를 시작할때 타이머가 작동하므로 독자적인 timer를 만들어서 사용한 것이 아니라면 user32.dll중에 settimer를 사용할 것이라고 가정하여 프로그램의 도입부분을 찾아내었다.





01003818에서 CMP를 통하여 DS:[010057A4]=00000000의 값과 0을 비교한다.

만약에 프로그램이 처음이 아니면 DS:[010057A4]=00000000의 값이 DS:[010057A4]=00000001이런식으로 바뀌므로

아래의 JNZ를 통하여 처음이면 타이머를 설정하기위하여 그대로 내려가고 처음이 아니라면 

0100386B  |> 841D 00500001  TEST BYTE PTR DS:[1005000],BL            ;  처음아니면 일로옴

이곳으로 내려가게된다.


지뢰찾기에서 맨처음은 항상 통과한다는것을 찾아내었다.

지뢰정보는 덤프 1005340에 담겨있다.


그림을 보면 현재 1,3이 지뢰인것을 알 수 있다. (위의 사이트 참조)

0100389B  |. 8A9402 4053000>MOV DL,BYTE PTR DS:[EDX+EAX+1005340] 에 브레이크 포인트를 걸어준뒤

1,3의 좌표를 누르면



누른부분의 좌표의 값이 8F에서 80으로 바뀌게된다. 원래 지뢰를 누르면 일단 그자리의 값이 80으로 바뀐다. (나중에 설명함)

이후 계속 돌리면 



분명 지뢰였던 부분이 지뢰가 아닌것으로 바뀌게된다. 맨처음일때 걸렸으면 알아서 수정해주는 기능이 있는것으로 보인다. 하지만 이부분은 더 깊이 조사할 생각은 없다.


그 이후 지뢰에대한 데이터가 저장되어있는것은 위의 페이지에 상세하게 나와있으므로 생략하고 나는 지뢰를 눌렀을때의 작동원리를 살펴보겠다.



먼저 다시 새로 시작한뒤에 맨처음에는 지뢰를 누르면 바뀌어버리기 때문에 정상적인 칸을 눌러주고 지뢰를 누르자.

위의 사진을 보면 2,2가 지뢰다. 따라서 1,2를 누른뒤 2,2를 누르겠다.


그러면 다시 2,2의 좌표가 80으로 바뀐다.

그렇다면 분명 코드중에 80과 비교하는 코드가 있을것이다. 그것을 찾아보았다.


어느정도 따라가다보면 

01003529  |. F602 80        TEST BYTE PTR DS:[EDX],80

의 코드를 볼 수 있다.[EDX]에 담긴 값과 80을 비교하라고 하는데 코드를 읽어보면 EDX에 사용자가 누른 값의 데이터의 주소를 넣어놓았으므로 실질적으로는

01003529  |. F602 80        TEST 80,80 인 상태다.

지뢰를 의미하는 것끼리 비교하라는 것이니까 무언가 느낌이 지뢰를 판별하려는 것임을 알수있다.

한번 테스트용으로 아래의 JE에서 원래는 점프가 일어나면 안되지만 0인 ZF를 1로 바꾸어 진행시켜보았다.

따라서 아래의 JE문에서 점프가 발생하였다.

그리고 진행시켜보면 지뢰찾기 프로그램에서 지뢰가 아니라고 뜨는 것을 알 수 있다.

지뢰정보를 보면 정보가 약간 모순적이게도 지뢰였던 자신과 오른쪽의 지뢰를 합쳐 주변에 지뢰가 2개있다고 말해준다. 또한 판에 있는 8F의 개수를 세어보면 지뢰가 총 9개밖에 안된다.

한번 클리어를 해보았다.


분명 지뢰는 9개이며 이상한 칸도 있지만 클리어는 하였다.

위의 TEST 80부분이 지뢰인지 판단하는 핵심기능임을 알 수 있다.


다음은 이 정보들을 토대로 지뢰찾기를 자동으로 클리어해주는 매크로를 만들고자 한다.


못깨는 지뢰찾기.exe

그전에 test부분을 수정하여 누르는 곳이 어디던 항상 틀림표시 되도록하는 못깨는 지뢰찾기를 만들어보았다.

친구를 골탕먹이기 좋을것같다.


지뢰찾기 매크로

반응형

'보안 > 리버싱' 카테고리의 다른 글

C# - minesweepr hack + macro  (0) 2017.02.06
반응형

uva id:100

#include <stdio.h>


int algo(int input);

int main()

{

int i, j, max;

while (scanf("%d %d", &i, &j) == 2 && i > 0 && j > 0 && j < 1000000 && i < 1000000)

{

printf("%d %d ", i, j);

if (j < i)

{

int k = j;

j = i;

i = k;

}

for (max = 1; i <= j; i++)

{

if (algo(i) >= max)

max = algo(i);

}

printf("%d\n", max);

}

return 0;

}

int algo(int input)

{

int n = 1;

while (input != 1)

{

if (input % 2 == 0)

{

input /= 2;

}

else

{

input = input * 3 + 1;

}

n++;

}

return n;

}

18455482100The 3n + 1 problemAcceptedANSI C0.3302016-12-05 05:47:50

//앞뒤순서 안바꿔줘서 에러가 났음.

반응형
반응형

Sprite의 이미지에서 노가다 형태로 긁어오는 수밖에 없는 것 같음.

반응형
반응형

for(var i=0;i<5;i++)

{

function asd(i) {

  console.log(i+3);

}

}

을 하면 분명 3 4 5 6 7 이 나와야 하지만

7 7 7 7 7이 나온다.


정말 골치아픈 문제였다.

분명 작동은 하는데 반복문 안의 함수가 맨 마지막 i값으로만 처리가 되버린다.

처음에는 어이가 없었음.


아마도 meanstack의 동기처리 때문에 그런듯 하다. (동기처리가 정말 밉더라)

http://apple77y.tistory.com/11


해결법으로는 3가지를 찾았음.


1. 반복문 안의 함수를 반복문 밖에서 선언한뒤에 parameter를 사용하여 정상적으로 수행.

근데 내가 만든 기능이 find안에 find를 또쓰는거라서 너무 복잡해버리게되어서 2번으로 해본뒤에 2번으로 쓰기로함.

function asd(num) {

  return (num+3);

}

이런식으로 만든뒤에

for(var i=0;i<5;i++)

{

asd(i);

}

대충 이런식?


2. With ({ n : i }) { ... }를 이용하여 정상적으로 수행.

function test() {

  for (var i = 0; i < 5; i++) {

       with ({ n: i }) {

      function asd() {

console.log(n+3);

}

    }

  }

}

.이런느낌? 개인적으로 2번보다 깔쌈한것같음.

3. Promise 기능을 사용하여 수행.

먼가 고급스러운 해결방법같지만 너무 어려워보여서 싫었음.


http://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue

반응형
반응형


UserModel.find({}, function (err, users) {

    return res.end(JSON.stringify(users));

}

이와 같은 형태로

Mongoose에서 찾은 json데이터를 넘길때 throw new TypeError('first argument must be a string or Buffer'); 에러가 뜬다.


이 에러는 Mongoose 객체가 Json 객체와는 별도이기 때문에 JSON.stringify 함수가 작동을 하지 않는 것이다.

따라서 find에 .lean()을 붙여주어 Json 객체로 바꿔준다.


UserModel.find().lean().exec(function (err, users) {

    return res.end(JSON.stringify(users));

}


http://stackoverflow.com/questions/9952649/convert-mongoose-docs-to-json



반응형
반응형

var User = mongoose.model('user', dataSchema);

라고 하면 User 몽구스 모델이 user 콜렉션을 참조하는 것이 아니라 users를 참조함.


따라서 스키마를 만들때 콜렉션의 이름을 지정해줘야함

var schema = new Schema({ name: String }, { collection: 'actor' });

이와같은 형태로 스키마를 만들때 콜렉션 이름을 지정해주면 제대로 불러옴.


http://stackoverflow.com/questions/10547118/why-does-mongoose-always-add-an-s-to-the-end-of-my-collection-name


반응형
반응형

원리


1. html에서 post방식으로 서버에 신호를 보냄.


<script>
app.controller('myCtrl', function($scope, $http) {    
    $scope.liked = function() {
        $http.post('/').
        success(function(data) {
            $scope.test=data; // post에 대한 서버로부터의 응답을 html의 test라는 것에 넣어줌
        }).error(function() {
        })
    };
});
</script>

컨트롤러는 알아서 설정하고

아무곳에 ng-click="liked()" 집어넣음.

이렇게 해놓으면 liked함수가 실행되면서 위의 스크립트가 작동함.




2. 서버에서 올바른 신호를 받으면 db 관련 데이터 처리

db는 mongoose로했음.

일단 먼저 몽구스 모듈 불러오고 연결함.

가장 중요한것 은 모델, 스키마를 잘 설정하는것

스키마 설정 예시

var userSchema = new mongoose.Schema({

like: {type:Number},

info:{type:String}

});

이거 타입을 잘맞춰줘야함.


이것만 잘 설정해도 거의 모든 에러가 다 사라짐. (모델, 스키마를 잘못 설정해서 에러가 엄청많이 떴음)

에러는 안나지만 세이브가 안되는 에러 해결됨

업데이트할때 like 가 하나 더생겨버리고 NAN 생기는 에러 사라짐

[ { _id: '576cd52ed5ea2827f765a5a0', like: 0, info: 'like' },  like: NaN ]

TypeError: User.save is not a function 에러도 사라짐





3. 서버에서 처리한 데이터를 html로 다시 보냄

res.end(documents[0].like+""); 

이러면 like넘버가 알아서 data변수로 html로 넘어감



4. html에서는 post에 대한 응답으로 받은 데이터를 다시 html에 나타내줌

$scope.test=data;

반응형
반응형

몽고db와 몽구스는 엄연히 다르다

몽고db가 더욱 큰 개념인데

몽구스는 몽고db 드라이버라고 불린다.

몽고db 드라이버는 마치 몽고db의 플러그인같은 개념인데

몽구스라는 드라이버를 사용하게 되면서 얻는 이점은

db의 스키마를 설정할수있다.

다시 말하자면 몽구스를 사용하지 않는 몽고db는 스키마없이 데이터만 꾸역꾸역 집어넣기만 한다.


하지만 몽구스같은 드라이버를 사용하게되면 코드가 더욱 복잡해지며 데이터 처리가 복잡해지기 때문에 연산에서 에러가 날 가능성이 높아진다고 한다.


참고

http://stackoverflow.com/questions/28712248/difference-between-mongodb-and-mongoose

반응형
반응형

var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test');


cloud9에서는 위와같이하면 작동함.

반응형