Well, maybe this is not a news. I've just added my new perk into the game.
Yes, this is for Mapper only (but all needed offsets can be found in FO too). Yes, this is not "adding" but "replacing unused". But it works.
The main idea is to replace unused "Mental block" with something that would be more use. Mental block was not comletely removed, BIS simply put 310 as needed level for this perk

How to change this:
1. 0x15abb4: replace [36 01] with [01 00] (min_level=1) or greater
2. replace fields with stats/skills being modified and modified ammount (see table two posts up). For example, replace this:
-----------------------------------------------
00 00 00 00-00 00 00 00 63 00 00 00
01 00 00 00 36 01 00 00-FF FF FF FF 00 00 00 00
FF FF FF FF 00 00 00 00-00 00 00 00 FF FF FF FF
00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
-----------------------------------------------
with this:
-----------------------------------------------
00 00 00 00-00 00 00 00 63 00 00 00
01 00 00 00 03 00 00 00-09 00 00 00 0A 00 00 00
FF FF FF FF 00 00 00 00-00 00 00 00 FF FF FF FF
00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
-----------------------------------------------
This add 10 AC, perk has no stats/skills requrment and would be apear on level 3.
3. modify perk.msg by replacing lines 128/1128 with your perk name/description
4. replace .frm
This way you can only add the stats/skills bonus perks. Perks like Bonus Rate of Fire are strictly hardcoded and used directly in game algorithms.
I`m sure there is weapon perks somewhere in this perk table...
[EDIT]
Some additions to Temaperacl work:
>>[00] - ? (Always 0000 0000)
>>[04] - ? (Always 0000 0000)
This fields contains pointer on strings with perk name/description. Of course, they initialize only when game starts, in exe this fields are always filled with 0.
>>[08] - ID (Appears to be ID in PERK.MSG -29)
It`s a number of .frm for perk from art\skilldex\skilldex.lst (started from 0).
Now I search for this Type field. Seems to me that it`s a flag, which says to engine how other fields (stat/skill_1/skill_2) should be parsed.