zed.0xff.me

Телефонное интервью в Google №1

(на самом деле не первое, а второе, первое было успешно провалено аж 4 года назад, из-за перенервничания)

Итак, сначала девушка-HR мне написала еmail, в котором мы договорились когда она мне позвонит по телефону. (все общение на английском языке конечно)

Потом она позвонила, спросила куда я хочу – в Дублин или Цюрих? Я удивился, ибо про Цюрих не знал ни сном ни духом… Думал только в Дублин зовут.

Еще сказала что у них есть Software Engineers, а есть Systems Engineers, короче техподдержка серверов и сервисов. Спросила меня куда я хочу, я сказал что не уверен. (но видимо мне таки ближе Systems Engineers :))

Потом начались технические вопросы, порядка 20 штук, довольно элементарные, разделенные на разделы:

  1. админство *nix
  2. алгоритмы
  3. структуры данных

Вопросы из разряда “что такое inode”, “сколько бит занимают права владельца файла в UNIX ACL”, “оцените время выполнения qsearch в worst case случае” (на последний я не ответил, ибо во всяких этих ваших N*log(N) не силен чуть более чем никак)

Вобщем на 1 вопрос я не ответил совсем, еще на 1 ответил на 2/3, а на все остальные ответил на 97-110% ;)

HR сказала что передаст мои ответы и резюме дальше по конвейеру и со мной свяжутся..

Дневник бортинженера авиакомпании "B***Y"

(все персонажи вымышлены, все совпадения с реальными личностями случайны)

Иногда пилоты обращаются ко мне
П: А вот если мы повернем сейчас на 17 градусов влево, то у нас крыло не отвалится?
Я: Хорошо что спросили. Отвалится. Давайте сейчас мои ребята выйдут на крыло, суперклеем намажут, а вы потом вправо повернете, и порезче! Кружок на месте сделаем, заодно и крыло подклеим, и повернем куда надо.
П: ОК

Иногда приходят списки пассажиров вот такого вида:
1. Иванов А.А., муж., Москва
2. Сидорова Е.И., жен., С.Петербург
3. Ъорлщхж М.Ф.У., аъы., Альфа-Центавра
4. Макаров И.А., муж., Курган
А на месте пассажира №3 либо пусто, либо обычный человек сидит. :(
Вот такие они, поставщики данных о пассажирах.

Есть у нас и стюардессы, кои обязаны пассажиров успокаивать, всяческие их потребности удовлетворять, а также быть связующим звеном между пассажирами и экипажем.
Пассажиры бывают разные. Один например глянет в иллюминатор, а там крыло отваливаться начинает, или еще какая напасть, так он тихо подзовет стюардессу, покажет пальчиком в окно, стюардесса передаст быстренько экипажу, мои ребята выбегут, подклеят там чегонить изолентой, мебельным степлером подстеплируют и все ОК. Летим дальше. Все довольны. Внимательному пассажиру бесплатный напиток.
А другой, например, увидит что турбина горит, и давай орать благим матом на весь салон. Приходится бедным стюардессам отдуваться, врать что это он не двигатель горит, а это праздничный салют в честь дня рождения второго пилота, ура-ура! И давай хороводы водить! Вобщем, успокоили.
А турбина? Ну погорит и перестанет, чай не последняя, у нас еще 5 штук есть )))

А недавно мы на лету избавились от карбюратора!!! Воткнули вместо него новенький инжектор (взяли подешевке на авторынке, от ВАЗ 21067, 2011 г.в.)
Совсем другие ощущения!
Какого хрена делал карбюратор на самолете… ума не приложу, вот так вот исторически сложилось.
Это я еще молчу о том что когда я пришел на этот самолет, тут турбины вообще крутили специально обученные белки! O_O Воняяяялооооо…. Бо́льшая часть багажного отсека была забита кормом для белок. Они еще и дохли периодически, а другие размножались. Приходилось как-то поддерживать баланс рождаемости-смертности белок, утилизировать их какашки и тельца, следить за тем чтобы они не бегали по салону и не кусали пассажиров…
Вобщем, инжектор – это просто манна небесная!

Туалет в самолете просто класс! Очень просторный (0.5х0.5х1.5м) и многофункциональный (поддерживаются функции PP и KK). Есть один небольшой нюанс. С вероятностью 10% незадачливого пассажира намертво присасывает к той самой дырке(давлением 4.04 psi), а с другой стороны, с вероятностью те же 10% оттуда прямо на пассажира начинает фонтанировать давлением 5.05 psi все его ужасное содержимое…
Но, как отметили 80% пассажиров: “у нас все получилось”, так что не ремонт туалета пока не заморачиваемся.
Подавляющее большинство довольно – значит все у нас хорошо!!

Авиакомпания у нас очень прибыльная. Потому что мы стремимся перевезти всех пассажиров, которые хотят лететь. Поэтому текущим ремонтом и даже усовершенствованием приходится заниматься в прямом смысле “на лету”.
Хорошо что у нас есть команда бесстрашных инженеров-механиков. Но не всегда хорошо что бесстрашных.

Например, инженер по приборам – очень толковый парень. Благодаря ему мы наконец-то можем в реальном времени видеть сколько у нас горючего в баках, заряд аккумуляторов, текущую скорость, и даже выпускать шасси!! (раньше шасси было как у “кукурузника” например)
Так вот, недавно он приделал классную штуку, альтиметр называется. “Теперь мы можем всегда знать нашу высоту полета! А не спрашивать языком жестов пролетающие мимо борта” – подумали мы.
Свежевключенный альтиметр показал высоту что-то около 56млн км над уровнем моря. O_O
– Какого моря?!
Южного
#(*$&^&#$(!!!!!
Так и живем…

Еще есть специалист по тонкой электронике. Может из волоска и батарейки приемник собрать. Телевизионный.
Взялся он как-то радар ремонтировать (что-то слишком много НЛО последнее время стал показывать)
Ремонтировал-ремонтировал. “Готово” – говорит.
Включаем. Работает. НЛО больше нет. Есть ОРТ. На радаре.
facepalm

  • Posted on July 29, 2014
  • Tagged b***y

demangle MSVC, Delphi & C++Builder mangled function names with pure Ruby

Ever wanted to convert @afunc$qxzcupi or ??3@YAXPAX@Z to something more human-readable?

(ofcourse you wanted, and you know about tdump.exe and undname.exe :)

And now you can do it using pure ruby, thanks to unmangler gem:

Unmangling Borland mangled names

1
2
3
4
5
6
7
8
require 'unmangler'

puts Unmangler.unmangle "@afunc$qxzcupi"
puts Unmangler.unmangle "@Forms@TApplication@SetTitle$qqrx17System@AnsiString"

# output:
# afunc(const signed char, int *)
# __fastcall Forms::TApplication::SetTitle(const System::AnsiString)

Unmangling MSVC mangled names

1
2
3
4
5
6
7
8
require 'unmangler'

puts Unmangler.unmangle "??3@YAXPAX@Z"
puts Unmangler.unmangle "?AFXSetTopLevelFrame@@YAXPAVCFrameWnd@@@Z"

# output:
# void __cdecl operator delete(void *)
# void __cdecl AFXSetTopLevelFrame(class CFrameWnd *)

And now w/o arguments

1
2
3
4
5
6
7
8
9
require 'unmangler'

puts Unmangler.unmangle "@Forms@TApplication@SetTitle$qqrx17System@AnsiString", :args => false

# outputs "Forms::TApplication::SetTitle"

puts Unmangler.unmangle "?AFXSetTopLevelFrame@@YAXPAVCFrameWnd@@@Z", :args => false

# outputs "AFXSetTopLevelFrame"

Links

  1. unmangler gem on rubygems.org
  2. unmangler sources on github.com

TBD: GCC support

Advanced Ruby: percent-literals

most used %-literals:

% code result description
%q %q(all `quotes` 'are' "ok") "all `quotes` 'are' \"ok\"" creates String
%r %r(i_am/a/regexp) /i_am\/a\/regexp/ creates Regexp
%w %w(abc def ghi) ["abc", "def", "ghi"] splits string into Array
%x %x(ls -a /tmp) ".\n..\nfile1\nfile2\n" alias of `cmd`

highlighted

1
2
3
4
5
6
7
%q(all `quotes` 'are' "ok") => "all `quotes` 'are' \"ok\""

%r(i_am/a/regexp)           => /i_am\/a\/regexp/

%w(abc def ghi)             => ["abc", "def", "ghi"]

%x(ls -a /tmp)              => ".\n..\nfile1\nfile2\n"

interpolation

1
2
3
4
5
6
7
8
9
10
11
# lowercase 'w': as-is
%w'a #{2+2} b' => ["a", "\#{2+2}", "b"] 

# uppercase 'W': interpolate
%W'a #{2+2} b' => ["a", "4", "b"] 

# lowercase 'q': as-is
%q'a #{2+2} b' => "a \#{2+2} b" 

# uppercase 'Q': interpolate
%Q'a #{2+2} b' => "a 4 b" 

other %-literals

1
2
3
4
5
6
7
8
# %s: convert to symbol
%s'foo' => :foo 

# %i: convert to array of symbols - not released yet, will be in Ruby 2.0 ?
%i'foo bar baz' => [:foo, :bar, :baz]

# '%' w/o any letter - alias for %Q
%'a #{2+2} b' => "a 4 b"

Advanced Ruby: break(value) & next(value)

1. break(value)

break accepts a value that supplies the result of the expression it is “breaking” out of:

1
2
3
4
5
  result = [1, 2, 3].each do |value|
    break value * 2 if value.even?
  end

  p result # prints 4

2. next(value)

next accepts an argument that can be used the result of the current block iteration:

1
2
3
4
5
6
7
  result = [1, 2, 3].map do |value|
    next value if value.even?

    value * 2
  end

  p result # prints [2, 2, 6]

Ruby: fastest way of converting string into array of characters

timecodecomment
0.147 s.bytes.to_amost fastest, but returns ASCII codes instead of chars
0.242 s.chars.to_a FASTEST
0.257 Array(s.chars)
0.265 a=[]; s.size.times{ |i| a<<s[i] }
0.268 a=[]; s.chars.each{ |c| a<<c }
0.278 s.bytes.map(&:chr)
0.513 s.scan(/./)
0.775 s.split(//)
0.795 s.split('') SLOWEST

first column is time of 100.000 iterations on Core i5 1.7GHz

code: bench-split.rb

bReader - Читалка цитатников, которая экономит ваше время и трафик

Особенные уникальности:

  • Поддержка картинок (xkcd, bash, что-то еще)
  • Цитаты обновляются через выделенный сервер обновлений, что:

    • гораздо быстрее, чем парсить HTML/XML на устройстве
    • экономит трафик, сжимая его и не загружая повторно то, что уже загружено
    • ВСЕ цитатники обновляются одним запросом, 2-3 секунды – и у вас уже 200 новых цитат

  • Все цитаты образуют единую ленту, но при желании можно читать любой цитатник отдельно.

  • Интеграция с твиттером (ну как без него) + все урлы жмутся через bit.ly, так что в один твит влезет больше полезного текста.

  • Читалка изначально заряжена 512-ю цитатами, так что даже в глуши без Интернета будет что почитать.

Изначально решил писать свою читалку потому что:

  1. надоело ждать когда уже одна небезызвестная читалка распарсит все свои источники
  2. при этом она еще и модальным окном загрузки все закрывает, хотя можно было бы и дать юзеру почитать то что есть, пока новое грузится
  3. в случае зависания сети/сайта/хз чего – висла вся программа, целиком и полностью
  4. некоторые цитатники (sramu.net) в RSS и на главной цитаты отдают не целиком, а половинку со ссылкой “читать дальше” – хотелось все-таки такие цитатники тоже читать нормально и без лишних кликов
  5. ну и комиксы тоже интересно было чтоб были

Немного технических фактов

  • итого на написание ушло полгода
  • сам читаю цитатники каждый день
  • AppStore аналогичное мое приложение отклонил, сволочь
  • backend: nginx, ruby, Sinatra, memcached
  • хостинг: Amazon EC2 small instance
  • IDE: VIM, rake

Все цитатники: (38шт)

QDBbash.org (English)
bash.altlinux.orgALT Linux Fortunator
bash.org.byЦитатник Байнета
bash.org.ruЦитатник Рунета
bash.org.ru комикскомиксы по мотивам цитат
besit2.ruесли накипело…
bezdna.suЛучшие цитаты из Бездны
comicsbook.ruFFFuuu, trollface, forever alone, okay и другие комиксы.
delonevtebe.ruДело не в тебе | Неудачные свидания
det.org.ruговорят дети
greatwords.ruВеликие слова — цитаты, афоризмы, высказывания
hatewall.ruстена ненависти
ibash.org.ruНовый цитатник Рунета
inwebwetrust комиксКомиксы об Интернете
ipfw.ruЦитатник канала #FreeBSD@RusNET
ithappens.ruКлиент и саппорт. Разработчик и заказчик. Программист и программа.
killmepls.ruКилл Ми Плз: Жизнь. Вид сзади.
kstatida.ruКороткие полезные советы, основанные на личном жизненном опыте, иногда печальном.
la2bash.ruLineage 2 беседка
lorquotes.ruLatest fortunes from Linux.Org.Ru.
nefart.ruВот такой не фарт!
nextjoke.netСамые смешные шутки
pinator.orgКраткие мотивирующие высказывания
pip.ecСегодня был ППЦ
polniyp.meПолный П!
psyhumor.ruПсихологи шутят
shortiki.comкороткие и смешные
sramu.netпостыдные истории, рассказанные реальными людьми
ukrbash.orgУкрБаш — український цитатник
wgbash.orgWorld of Tanks
wumocomicstrip.comWumo by Wulff & Morgenthaler – a commentary on life
xkcd.comA webcomic of romance, sarcasm, math, and language.
xkcd.ruxkcd по-русски
zadolba.liзадолба!ли
жж ellustratorЖЖ: Картинки здесь!
жж pirozhki-ruЖЖ: Пирожковая
жж poroshkiЖЖ: Порошки: кристаллизованная поэзия
жж ru-comicstripЖЖ: комиксы на русском

Скриншотики

Photobucket Photobucket Photobucket Photobucket Photobucket

Скачать

bReader в Google.Play

grub2 simple hardware boot switch

1. take any old unused USB stick (any size, 16M is more than enough, mine was 128M)

#fdisk -l /dev/sdc
Disk /dev/sdc: 126 MB, 126353408 bytes
16 heads, 32 sectors/track, 482 cylinders, total 246784 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x59d30b2a

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1   *          32      246271      123120   83  Linux

2. [optional] format it to ext2

3. find out its UUID

#blkid /dev/sdc*
/dev/sdc1: UUID="3a5ef90f-0640-42c3-97c2-8743c822ba60" TYPE="ext2"

4. do some simple grub2 scripting:

menuentry "auto" {
        set foo_uuid=3a5ef90f-0640-42c3-97c2-8743c822ba60
        set foo=empty

        insmod part_gpt
        insmod ext2
        insmod search_fs_uuid

        search --fs-uuid --no-floppy --set=foo $foo_uuid

        if [ $foo = "empty" ]; then
                # boot windows
                insmod fat
                insmod chain
                search --fs-uuid --no-floppy --set=root B0D7-DA71
                chainloader (${root})/efi/Microsoft/Boot/bootmgfw.efi
        else
                # boot linux
                set root='(hd0,gpt1)'
                search --no-floppy --fs-uuid --set=root 22c0603d-670e-4097-83d2-539b520fc75a
                linux /boot/vmlinuz root=/dev/sda1
        fi
}

So, if this (and exactly this, with unique UUID) USB stick is plugged in while computer boots – it will boot Linux, otherwise Windows will boot.

Dwarf Fortress

Первая цивилизация погибла от (пары) злобных гоблинов.

Вторая тоже =).

Третья научилась строить ДВЕРЬ(!!!) на входе в поселение. Погибла от злобного тролля, который умел ломать двери.

Четвертая погибла от жажды. Потому что все речки и озера зимой замерзли, до подземных источников она докопаться не успела, а как из льда добыть воду не дотумкала.

Пятая сейчас погибает от.. обновления 34.07, после которого дети вдруг стали паниковать по поводу своей одежды (ее отсутствия или поношенности, а новую надевать не хотят) и сходить с ума..

раскодируем Trojan.Siggen3.35000

лечение

обнаружение

Попался мне как-то в руки троянчик.
Вот его анализ на pedump.me
Вот так он обнаруживается различными антивирусами:

AntiVir: TR/Offend.6610086.8
BitDefender: Trojan.Generic.6610086
ClamAV: Trojan.Dropper-31300
DrWeb: Trojan.Siggen3.35000
Emsisoft: Trojan.SuspectCRC!IK
F-Secure: Trojan.Generic.6610086
Fortinet: W32/Filecoder.AA
GData: Trojan.Generic.6610086
Ikarus: Trojan.SuspectCRC
K7AntiVirus: Riskware
Kaspersky: UDS:DangerousObject.Multi.Generic
McAfee: Artemis!2A8242105FED
NOD32: Win32/Filecoder.AA
Norman: W32/Malware.WVNX
Panda: Trj/CI.A
TheHacker: Trojan/Filecoder.ab

полный отчет на virustotal.com

анализ

троян портит JPG, DOC, XLS файлы. Обнаружить испорченные файлы можно визуально по следующему куску данных в конце файла:

1
2
3
4
5
6
7
8
9
10
001a2cfb:  34 36 34 36 34 34 33 38  34 36 34 36 34 35 33 31  |4646443846464531|
001a2d0b:  33 32 33 35 34 36 34 36  34 36 34 36 33 30 33 31  |3235464646463031|
001a2d1b:  33 30 33 30 33 30 33 30  33 30 33 30 33 30 33 30  |3030303030303030|
001a2d2b:  33 30 33 30 33 30 33 30  33 30 33 30 33 30 33 30  |3030303030303030|
001a2d3b:  33 30 33 30 33 30 33 30  33 30 33 30 33 30 33 30  |3030303030303030|
001a2d4b:  33 30 33 30 33 30 33 30  33 30 33 30 33 30 33 30  |3030303030303030|
001a2d5b:  33 30 33 30 14 00 00 00  00 fb 2c 1a 00 14 00 04  |3030......,.....|
001a2d6b:  00 00 0f 2d 1a 00 14 00  08 00 00 23 2d 1a 00 14  |...-.......#-...|
001a2d7b:  00 0c 00 00 37 2d 1a 00  14 00 10 00 00 4b 2d 1a  |....7-.......K-.|
001a2d8b:  00 05 

(конкретные данные различны в зависимости от содержимого файла)

результат бинарного сравнения нормального (слева) и испорченного (справа) файла:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
00000000: ff 54
00000001: d8 2f
00000002: ff 54
00000003: e1 38
00000004: 25 7a
00000400: ff 54
00000401: ff 56
00000402: 01 56
00000403: 00 57
00000404: 00 55
00000800: 00 54
00000801: 00 51
00000802: 00 54
00000803: 00 51
00000804: 00 54
00000c00: 00 54
00000c01: 00 51
00000c02: 00 54
00000c03: 00 51
00000c04: 00 54
00001000: 00 54
00001001: 00 51
00001002: 00 54
00001003: 00 51
00001004: 00 54

[!]           168_ok.jpg is  1715451 bytes long
[!]          168_bad.jpg is  1715597 bytes long

фактически троян портит по 5 байт в файле с интервалом в 1024 байта. но не просто портит, а записывает оригинал в конец испорченного файла. вот наглядный вид чего он там понаписал:

1
2
3
4
5
6
001a2d5f:  14  00 00 00 00  fb 2c 1a 00  |......,..|
001a2d68:  14  00 04 00 00  0f 2d 1a 00  |......-..|
001a2d71:  14  00 08 00 00  23 2d 1a 00  |.....#-..|
001a2d7a:  14  00 0c 00 00  37 2d 1a 00  |.....7-..|
001a2d83:  14  00 10 00 00  4b 2d 1a 00  |.....K-..|
001a2d8c:  05         

radare2 0.8.x unnecessary memory zeroing fix

radare2 bug

the bug only appears when debugging 32-bit binary on a 64-bit host

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
diff -r e96275c214b5 libr/io/p/io_ptrace.c
--- a/libr/io/p/io_ptrace.c        Mon Oct 24 04:35:42 2011 +0200
+++ b/libr/io/p/io_ptrace.c        Mon Oct 24 16:48:31 2011 +0300
@@ -34,9 +34,11 @@
 #if __OpenBSD__ || __KFBSD__
 #define debug_read_raw(x,y) ptrace(PTRACE_PEEKTEXT, (pid_t)(x), (caddr_t)(y), 0)
 #define debug_write_raw(x,y,z) ptrace(PTRACE_POKEDATA, (pid_t)(x), (caddr_t)(y), (int)(size_t)(z))
+typedef int ptrace_word;   // int ptrace(int request, pid_t pid, caddr_t addr, int data);
 #else
 #define debug_read_raw(x,y) ptrace(PTRACE_PEEKTEXT, x, y, 0)
 #define debug_write_raw(x,y,z) ptrace(PTRACE_POKEDATA, x, y, z)
+typedef void* ptrace_word; // long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
 #endif
 
 static int debug_os_read_at(int pid, ut32 *buf, int sz, ut64 addr) {
@@ -63,10 +65,11 @@
 }
 
 static int ptrace_write_at(int pid, const ut8 *pbuf, int sz, ut64 addr) {
-        ut32 *buf = (ut32*)pbuf;
-        ut32 words = sz / sizeof (ut32);
-        ut32 last = sz % sizeof (ut32);
-        ut32 x, lr, *at = (ut32*)(size_t)addr;
+        ptrace_word *buf = (ptrace_word*)pbuf;
+        ut32 words = sz / sizeof (ptrace_word);
+        ut32 last = sz % sizeof (ptrace_word);
+        ut32 x, *at = (ptrace_word*)(size_t)addr;
+        ptrace_word lr;
         if (sz<1 || addr==UT64_MAX)
                 return -1;
         for (x=0; x<words; x++)

printing from OSX & iOS to Canon MF-4018 shared via WNDR3700

0. Reason for this all

HP Photosmart 5510

Just bought an HP Photosmart 5510 with wifi & ePrint and my MacBook Air found and installed it via wifi without the need of any drivers or anything.

Canon MF4018

But I also have older Canon MF4018, connected directly to WNDR3700 via usb, and which I failed to set up for printing from my Macs via wifi.

1. Drivers

Netgear WNDR3700

The main reason why I failed is Canon’s drivers for MF4018 (or MF4010, their printing functions are the same). They only have more or less usable drivers for Windows and Linux, closed-source and bad designed, with a lot of proprietary stuff.

There is a way to make your OpenWRT router act like a print server for Windows & Linux clients, but it refuses to work with OSX client.

And even if we’ll somehow force it to work with OSX client, it will still need a lot of Canon drivers installed on Mac and carefully configured. And definitely will not work with iOS

2. Workaround

You can use one simple workaround if you have an x86 or x86_64 computer running 24/7 at your place. Or if you want to manually turn it on every time when you need to print something.

You can then install CUPS on your device, or use a Windows Printer Sharing.

Unacceptable for me. I only have WNDR3700 on ar71xx platform, and AppleTV2 on ARM Cortex A8 running nearly 24/7 at my home.

3. An Insight

If I can’t run an x86 PC 24/7 at my place — who or what can stop me to run it somewhere on Internet?!

(I already have a pair of servers on Internet, so let’s increase their load average a little :)

IMPORTANT: You’ll need to have a Real IP address at your place, or some other way of receiving data from your Internet server, like a SSH tunnel.

4. Step-by-step guide

  1. WNDR3700 (or other OpenWrt-based router, or DD-WRT one, or wl500g)
    1. Connect MF4018 via usb
    2. Set up p910nd
    3. Open port 9100 in firewall:
      iptables -A INPUT -j ACCEPT -p tcp -s your.internet.server.real.ip --dport 9100
  2. Internet server
    1. install CUPS
    2. install Canon Proprietary drivers: for example UFRII/UFRII LT Printer Driver for Linux v2.20
    3. Add a printer:
      lpadmin -p mf4010 -P CNCUPSMF4010ZK.ppd -v socket://my.home.real.ip:9100 -o printer-is-shared=true
    4. enable CUPS Internet sharing:
    5. set up CUPS and/or firewall to only allow connections from YOUR home/office network
  3. Optional steps, needed only for seamless printer autoconfiguration for OSX/iOS devices
    1. Configure
      1. Internet server: use airprint-generate to generate a .service file for your printer
      2. edit generated file: add <host-name>my.internet.server.real.ip</host-name>
      3. WNDR3700: install avahi-daemon, feed it with previously generated file, start it
    2. Now in OSX “Add Printers” Dialog just click “+” and it should see your printer, iOS should see your printer when you’ll try to print some photo

my autogenerated & edited mf4010.service file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">Canon MF4018</name>
  <service>
    <type>_ipp._tcp</type>
    <subtype>_universal._sub._ipp._tcp</subtype>
    <port>631</port>
    <host-name>my.internet.server.real.ip</host-name>       <!-- EDIT THIS -->
    <txt-record>txtvers=1</txt-record>
    <txt-record>qtotal=1</txt-record>
    <txt-record>Transparent=T</txt-record>
    <txt-record>URF=none</txt-record>
    <txt-record>rp=printers/mf4010</txt-record>
    <txt-record>note=laser</txt-record>
    <txt-record>product=(GPL Ghostscript)</txt-record>
    <txt-record>printer-state=3</txt-record>
    <txt-record>printer-type=0x821484</txt-record>
    <txt-record>pdl=application/octet-stream,application/pdf,application/postscript,image/gif,image/jpeg,image/png,image/tiff,text/html,text/plain,application/vnd.cups-banner,application/vnd.cups-postscript,application/vnd.cups-raw,application/vnd.hp-hpgl,image/x-bitmap</txt-record>
  </service>
</service-group>

hack.lu 2011 CTF -- Unknown Planet -- writeup

[ Lobotomy ]

0. original image file

1. analyzing image

all JPEGs have special EOF marker FF D9 and no data must be after this marker.

1
2
3
4
5
[zed@zmac 200.unknown.planet+]#irb -E binary
ruby-1.9.2-p290 :004 > data=File.read '0_8c4f14e28155a2c3cf4b2538c1e0958b.jpg'; data.size
 => 194420 
ruby-1.9.2-p290 :005 > data.split("\xff\xd9").map(&:size)
 => [192405, 2013] 

so, we can see that there’s 2013 spare bytes after EOF marker.

1
2
3
4
5
6
File.open('foo','w'){ |f| f<< data.split("\xff\xd9").last }
 => #<File:foo (closed)> 
ruby-1.9.2-p290 :007 > ^D

[zed@zmac 200.unknown.planet+]#file foo
foo: Zip archive data, at least v2.0 to extract

AHA! It’s a zip! :)

2. unzipping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[zed@zmac 200.unknown.planet+]#unzip foo 
Archive:  foo
  inflating: 5IIUED7GheR             
  inflating: 6JXtwsTTh9k             
  inflating: 87F1s5POUJc             
  inflating: BPiIOASG_Z6             
  inflating: nLPA8X0UJqf             
  inflating: rySOWi4fZkA             
  inflating: uvlSlG3Tgow             
  inflating: Uw105aD3qYh             
  inflating: Yui5oq58hlx    


[zed@zmac 200.unknown.planet+]#ls -la
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 5IIUED7GheR
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 6JXtwsTTh9k
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 87F1s5POUJc
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 BPiIOASG_Z6
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 Uw105aD3qYh
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 Yui5oq58hlx
-rw-r--r--@  1 zed  staff   1324 Apr 25 16:45 nLPA8X0UJqf
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 rySOWi4fZkA
-rw-r--r--@  1 zed  staff  20000 Apr 25 16:45 uvlSlG3Tgow

[zed@zmac 200.unknown.planet+]#file *
5IIUED7GheR: data
6JXtwsTTh9k: data
87F1s5POUJc: 8086 relocatable (Microsoft)
BPiIOASG_Z6: data
Uw105aD3qYh: data
Yui5oq58hlx: data
nLPA8X0UJqf: 8086 relocatable (Microsoft)
rySOWi4fZkA: data
uvlSlG3Tgow: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 8000 Hz

Looks like audio file, that was split in chunks of 20000 bytes each.
uvlSlG3Tgow is a first chunk b/c it has a RIFF WAVE header.
nLPA8X0UJqf is a last tail chunk b/c it’s size less than 20000.

3. gluing waves

importing files in Audacity (or any other sound editor) discovers that source file is supposed to be a Morse – coded message. But we must find a correct order of chunks.
So, morse code consists of dots and dashes. Each kind must have fixed length.
We suppose that source file was generated programmatically, not recorder from line or mic. So, it’s timings must be perfect.
Following tool helps to manually find a correct chunks order.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env ruby
STDOUT.sync = true

if ARGV.size == 0
  raise "gimme at least one chunk filename"
end

b0 = "\x80"*8
b1 = "\x27\x01\x27\x80\xd9\xff\xd9\x80"

data = ARGV.map{ |x| File.read(x) }.join.force_encoding('binary')
if data[0,4] == 'RIFF'
  data = data[44..-1]
end

N=120

b0 = b0*N
b1 = b1*N

r = ''
0.step(data.size-1,b0.size) do |i|
  case (d=data[i,b0.size])
  when b0
    print "."
    r << '0'
  when b1
    print "#"
    r << '1'
  else
    raise "SYNC ERROR" if d.size == b0.size
    raise "NOT ENOUGH DATA #{d.size}/#{b0.size}"
    raise "unknown #{d.size} (normal: #{b0.size}) bytes of data #{d.split('').map{|x| "%02x " % x.ord}.join}"
  end
end

calling with a single chunk – script says that it needs more data (more chunks):

1
2
[zed@zmac 1]#./2_manually_guess_chunk_order.rb uvlSlG3Tgow 
##..######..######.../2_manually_guess_chunk_order.rb:32:in `block in <main>': NOT ENOUGH DATA 756/960

calling with wrong 2nd chunk => SYNC ERROR:

1
2
[zed@zmac 1]#./2_manually_guess_chunk_order.rb uvlSlG3Tgow 6JXtwsTTh9k 
##..######..######..###./2_manually_guess_chunk_order.rb:31:in `block in <main>': SYNC ERROR 

two chunks in correct order, script says it needs more chunks:

1
2
[zed@zmac 1]#./2_manually_guess_chunk_order.rb uvlSlG3Tgow 5IIUED7GheR 
##..######..######..##......##..##..##..#./2_manually_guess_chunk_order.rb:32:in `block in <main>': NOT ENOUGH DATA 596/960 

all chunks in correct order:

1
2
[zed@zmac 1]#./2_manually_guess_chunk_order.rb uvlSlG3Tgow 5IIUED7GheR rySOWi4fZkA 87F1s5POUJc 6JXtwsTTh9k Uw105aD3qYh BPiIOASG_Z6 Yui5oq58hlx nLPA8X0UJqf 
##..######..######..##......##..##..##..##......##......##..##......######..##..######......######..##..######..######......######..######..######......##..##..##......

4. decoding Morse

we’ll need a ruby morse gem. install it with “gem install morse

1
2
3
4
5
6
[zed@zmac 200.unknown.planet+]#irb
ruby-1.9.2-p290 :001 > r='##..######..######..##......##..##..##..##......##......##..##......######..##..######......######..##..######..######......######..######..######......##..##..##......'
ruby-1.9.2-p290 :002 > require 'morse'
 => true 
ruby-1.9.2-p290 :005 > puts Morse.decode(r.gsub('......'," ").gsub('######','-').gsub('.','').gsub('##','.'))
PHEIKYOS

Voila! “Pheikyos” is the answer. Case-sensitive.

PS: all source & data files are available at my ctf github repo.

iphone glossy buttons howto

sample images

one big sample image33 individual button images











ObjC code

Following ObjC code uses iphone Private API (UIGlassButton class), so it may be rejected from AppStore.
BUT you can generate a lot of iphone-style glossy button images with it, save to PNG, and use in your projects.

IMPORTANT: this code must be run on iPhone simulator. it saves PNG images to /tmp folder on your computer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define UIColorFromRGBA(rgbValue,a) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
  green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
  blue:((float)(rgbValue & 0xFF))/255.0 alpha:a]

Class theClass = NSClassFromString(@"UIGlassButton");

for(int j=0;j<3;j++){
    for(int i=0;i<=10;i++){
        UIButton *theButton = [[[theClass alloc] initWithFrame:CGRectMake(5+120*j, 5+i*44, 120, 44)] autorelease];
        [theButton setValue:UIColorFromRGBA(0xff<<(j*8),0.1*i) forKey:@"tintColor"];
        //[theButton setTitle:@"Accept" forState:UIControlStateNormal];
        [self.view addSubview:theButton];
        
        UIGraphicsBeginImageContext(theButton.frame.size);
        CGContextRef theContext = UIGraphicsGetCurrentContext();
        [theButton.layer renderInContext:theContext];
        
        UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
        NSData *theData = UIImagePNGRepresentation(theImage);
        [theData writeToFile:[NSString stringWithFormat:
                              @"/tmp/btn%@%02i.png",
                              j==0 ? @"B" : (j==1 ? @"G" : @"R"),
                              i] atomically:NO];
        
        UIGraphicsEndImageContext();
    }
}

and now make them stretch

automatically stretching to
(oops, button lost a shadow during screen capture, not important here though)

note that stretchableImageWithLeftCapWidth method:

1
2
3
4
            UIButton* button = [[UIButton alloc] init];
            [button setTitle:@"  looong long long very long text  " forState:UIControlStateNormal];
            [button setBackgroundImage:[[UIImage imageNamed:@"btnB10.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateNormal];
            [button sizeToFit];

NB: Don’t forget to release a button ! :)

Наноисследование твиттера :)

1. Очевидный факт – минимальная длина юзернейма в твиттере = 1 символ

примеры: @a @b @0
естественно, на данный момент они уже все давно заняты :)

2. Не всякий @lol это LOL и не всякий @nike это Nike

примеры:

@nike 1K followers 0 tweets ни разу не найк
@adidas 4K followers 170 tweets вроде как адидас
@puma 21K followers 1200 tweets аутентичная пума
@sela 46 followers 4 tweets какой-то мужик
@mcdonalds 163K followers 5500 tweets аутентичный макдак
 
@lol 800 followers 41 tweets совсем не смешно
@humor 1200 followers 13 tweets аналогично
 
@yandex 65K followers 800 tweets аутентичный яндекс
@google 3.5M followers 2800 tweets аутентичный гугл
@apple 2K followers 2 tweets не эппл ни разу

Вывод №1: популярный юзернейм вроде @apple или @humor может принести пару тысяч лишних фолловеров

Вывод №2: что следует сделать твиттеру

Твиттеру следует сделать возможность покупки уже существующих имен. Не принудительной естественно. Просто при заходе в чужой профиль кнопочка “I want to buy this username” и как на ебее – ставки, минимальная цена, аукцион (опционально) и т.п.
А может и сам владелец профиля у себя в настройках выставлять “I would sell this username for at least $5000”.
Соответственно если кто-то на эту кнопочку нажал, и сумму указал, он подтверждает что он не просто так нажал, а этим взял на себя обязательство в случае согласия владельца юзернейма купить его (юзернейм, а не владельца :) за указанную сумму.

  • Posted on September 04, 2011
  • Tagged twitter